第一个---定义项目return
- 在定义项目返回值的时候,可以利用泛型
-
@Data public class R<T> { private Integer code; //编码:1成功,0和其它数字为失败 private String msg; //错误信息 private T data; //数据 private Map map = new HashMap(); //动态数据 public static <T> R<T> success(T object) { R<T> r = new R<T>(); r.data = object; r.code = 1; return r; } public static <T> R<T> error(String msg) { R r = new R(); r.msg = msg; r.code = 0; return r; } public R<T> add(String key, Object value) { this.map.put(key, value); return this; } }
第二个---查看或者修改信息
- 在点击页面中某一个员工查看信息的时候,url路径上就带着id值,前端拿到之后返回给后端就可以了
-
@GetMapping("/{id}") public R<T> getById(@PathVariable Long id) { }
第三个---多使用mybatis-plus封装在IService接口和BaseMapper接口中的方法
第四个---全局异常捕获
-
/** * 全局异常处理 * 类上带annotations里面的注解都会被自动捕获异常 * 通过@ExceptionHandler来定义需要捕获异常的类型 * 代码实现捕获异常 */ @ControllerAdvice(annotations = {RestController.class, Controller.class}) @ResponseBody @Slf4j public class GlobalExceptionHandler { /** * 异常处理方法 * @return */ @ExceptionHandler(SQLIntegrityConstraintViolationException.class) public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) { log.error(ex.getMessage()); if(ex.getMessage().contains("Duplicate entry")) { String[] split = ex.getMessage().split(" "); String msg = split[2] + "已存在"; return R.error(msg); } return R.error("未知错误"); } }
第五个---对象映射器
- 第一段代码在common包里 第二段代码在config包里
-
/** * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象] * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON] */ @SuppressWarnings({"all"}) public class JacksonObjectMapper extends ObjectMapper { public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; public JacksonObjectMapper() { super(); //收到未知属性时不报异常 this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false); //反序列化时,属性不存在的兼容处理 this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); SimpleModule simpleModule = new SimpleModule() .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))) .addSerializer(BigInteger.class, ToStringSerializer.instance) .addSerializer(Long.class, ToStringSerializer.instance) .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT))) .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT))) .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT))); //注册功能模块 例如,可以添加自定义序列化器和反序列化器 this.registerModule(simpleModule); } } -
@Slf4j @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { /** * 扩展MVC框架的消息转换器 * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { log.info("扩展消息转换器..."); // 创建消息转换对象 MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); // 设置对象转换器,底层使用Jackson将Java对象转为json messageConverter.setObjectMapper(new JacksonObjectMapper()); // 将上面的消息转换器对象追加到mvc框架的转换器集合中 super.extendMessageConverters(converters); } }
第六个---设置静态资源映射
-
@Slf4j @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { /** * 设置静态资源映射 * @param registry */ @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info("开始静态资源映射..."); registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/"); registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/"); } }
第七个---公共字段自动填充
- 应用场景:当我们每个数据库中都有一些字段的时候,我们可以通过公共字段自动填充来做到每次添加或修改的时候自动进行填写数值
- 第一步--在实体类中需要自动填充的字段上添加@TableField注解
-
@TableField(fill = FieldFill.INSERT) // 插入时填充字段 private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时填充字段 private LocalDateTime updateTime; @TableField(fill = FieldFill.INSERT) // 插入时填充字段 private Long createUser; @TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时填充字段 private Long updateUser; - 第二步--编写common类进行字段填充
-
@Slf4j @SuppressWarnings({"all"}) public class MyMetaObjecthandler implements MetaObjectHandler { /** * 插入操作,自动填充 * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { log.info("公共字段自动填充[insert]..."); log.info(metaObject.toString()); metaObject.setValue("createTime",LocalDateTime.now()); metaObject.setValue("updateTime",LocalDateTime.now()); metaObject.setValue("createUser",BaseContext.getCurrentId()); metaObject.setValue("updateUser",BaseContext.getCurrentId()); } /** * 更新操作,自动填充 * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { log.info("公共字段自动填充[update]..."); log.info(metaObject.toString()); metaObject.setValue("updateTime",LocalDateTime.now()); metaObject.setValue("updateUser",BaseContext.getCurrentId()); } } - 第三点注意-----在自动填充id值的时候不能通过session进行获取,需要利用线程操作来进行获取
- 在登录过滤器中设置用户的id值,然后在公共自动填充字段实现类中获取用户的id值
-
// 4、判断登录状态,如果已登录,则直接放行 if(request.getSession().getAttribute("employee") != null) { log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee")); Long empId = (Long) request.getSession().getAttribute("employee"); BaseContext.setCurrentId(empId); filterChain.doFilter(request,response); return; } -
@Slf4j @SuppressWarnings({"all"}) public class MyMetaObjecthandler implements MetaObjectHandler { /** * 插入操作,自动填充 * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { log.info("公共字段自动填充[insert]..."); log.info(metaObject.toString()); metaObject.setValue("createTime",LocalDateTime.now()); metaObject.setValue("updateTime",LocalDateTime.now()); metaObject.setValue("createUser",BaseContext.getCurrentId()); metaObject.setValue("updateUser",BaseContext.getCurrentId()); } /** * 更新操作,自动填充 * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { log.info("公共字段自动填充[update]..."); log.info(metaObject.toString()); metaObject.setValue("updateTime",LocalDateTime.now()); metaObject.setValue("updateUser",BaseContext.getCurrentId()); } }
第八个--过滤器
- 判断登录状态,用过滤器来进行url的路径筛选和跳转
-
@Slf4j @SuppressWarnings({"all"}) @WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*") public class LoginCheckFilter implements Filter { // 路径匹配器,支持通配符 public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher(); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 1、获得本次请求的URI、 String requestURI = request.getRequestURI(); log.info("拦截到的请求:{}",requestURI); // 定义不需要处理的请求路径 String[] urls = new String[] { "/employee/login", "/employee/logout", "/backend/**", "/front/**" }; // 2、判断本次请求是否需要处理 boolean check = check(urls,requestURI); // 3、如果不需要处理,则直接放行 if(check) { log.info("本次请求{}不需要处理",requestURI); filterChain.doFilter(request,response); return; } // 4、判断登录状态,如果已登录,则直接放行 if(request.getSession().getAttribute("employee") != null) { log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee")); Long empId = (Long) request.getSession().getAttribute("employee"); BaseContext.setCurrentId(empId); filterChain.doFilter(request,response); return; } log.info("用户未登录"); // 5、如果未登录则返回未登录结果 response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN"))); return; } /** * 路径匹配,检查本次请求是否需要放行 * @param urls * @param requestURI * @return */ public boolean check(String[] urls,String requestURI) { for (String url : urls) { boolean match = PATH_MATCHER.match(url, requestURI); if(match) { return true; } } return false; } }