关于在Spring项目中一些封装的方法或工具类的总结

此篇文章介绍一些Spring项目中可能会用到的一些封装的好用的方法或一些工具类,在此记录一下!

请求资源映射方法,比如在请求接口前加上/api前缀的方法:

@Getter
@Configuration
public class ResourceMapping {
    
    

    /**
     * api包下统一前缀
     */
    private Api api = new Api("api", "**.controller.**");

    @Getter
    public static class Api {
    
    
        /**
         * 请求前缀
         */
        private String prefix;

        /**
         * 匹配包名
         */
        private String controllerPath;

        public Api(String prefix, String controllerPath) {
    
    
            this.prefix = prefix;
            this.controllerPath = controllerPath;
        }
    }
}

Api接口实现统一格式返回:

@RestControllerAdvice(basePackages = {
    
    "com.xxxx.api.xxxx.controller"})
public class GlobalResult implements ResponseBodyAdvice<Object> {
    
    

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
    
    
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {
    
    
        if (body instanceof RespBody) {
    
    
            return body;
        }
        RespBody<Object> respBody = ServerContext.getRespBody();
        if (!ObjectUtils.isEmpty(body)) {
    
    
            respBody.setBody(body);
        }
        if (body instanceof String) {
    
    
            return JSON.toJSONString(respBody);
        }
        return respBody;
    }
}

跨域设置:

@Slf4j
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CrossFilter implements Filter {
    
    

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
    
    
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;
        String origin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", origin);
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST,HEAD,PUT,GET,OPTIONS,DELETE,PATCH");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "System-Name,x-requested-with,Content-Type,Authorization,Credential,X-XSRF-TOKEN");
        if ("OPTIONS".equalsIgnoreCase(request.getMethod()) || "INCLUDE".equalsIgnoreCase(request.getMethod())) {
    
    
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
    
    
            chain.doFilter(req, resp);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    
    
        log.info("跨域过滤器启动");
    }

    @Override
    public void destroy() {
    
    
        log.info("跨域过滤器销毁");
    }
}

注册拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    

    @Autowired
    private ResourceMapping webProperties;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(new HandlerInterceptor() {
    
    
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
                return HandlerInterceptor.super.preHandle(request, response, handler);
            }

            @Override
            public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    
    
            }

            @Override
            public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
    
            }
        }).addPathPatterns("/**");
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
    
    
        // 根据不同包匹配表达式,添加各自的统一前缀
        configurePathMatch(configurer, webProperties.getApi());
    }

    /**
     * API 前缀:实现指定的controller 提供的 RESTFul API 的统一前缀(通过该前缀,避免Swagger,Actuator 意外通过Nginx暴露出来给外部,带来安全性问题)
     *
     * @param configurer
     * @param api
     */
    private void configurePathMatch(PathMatchConfigurer configurer, ResourceMapping.Api api) {
    
    
        // 创建路径匹配类,指定以'.'分隔
        AntPathMatcher antPathMatcher = new AntPathMatcher(".");
        // 指定匹配前缀 类上有RestController注解 && 该类的包名匹配指定的自定义包的表达式
        configurer.addPathPrefix(api.getPrefix(), clazz -> clazz.isAnnotationPresent(RestController.class) && antPathMatcher.match(api.getControllerPath(), clazz.getPackage().getName()));
    }
}

全局异常处理:

@Slf4j
@ControllerAdvice//不指定包默认加了@Controller和@RestController都能控制
public class GlobalException extends ExceptionHandlerExceptionResolver {
    
    

    @Override
    protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
    
    
        log.error("系统发生异常 当前请求 {} ,执行方法 {},异常信息 {}", request.getRequestURL().toString(), request.getMethod(), exception);
        //如果Controller用了@RestController注解或方法用了@ResponseBody注解则返回json对象,而不是转入error界面
        if (isAjax(handlerMethod)) {
    
    
            //创建默认返回对象,并设置异常信息
            RespBody<?> respBody = ServerContext.getRespBody();
            respBody.setCode(HttpStatus.ERROR.getValue());               //系统异常
            respBody.setMsg(HttpStatus.ERROR.getMsg());

            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Cache-Control", "no-cache, must-revalidate");
            try {
    
    
                response.flushBuffer();
                response.getWriter().write(JSON.toJSONString(respBody));
                return new ModelAndView();
            } catch (IOException e) {
    
    
                log.error("json转换错误");
            }
        }
        return new ModelAndView("redirect:/management/error");
    }

    /**
     * 权限异常
     *
     * @param e
     * @return 自定义返回数据
     */
    @ResponseBody
    @ExceptionHandler(AccessDeniedException.class)
    public RespBody<?> handleAccessException(AccessDeniedException e) {
    
    
        return ServerContext.getRespBody().code(HttpStatus.FORBIDDEN.getValue()).msg(e.getMessage());
    }

    /**
     * 自定义异常
     *
     * @param e
     * @return 自定义返回数据
     */
    @ResponseBody
    @ExceptionHandler(BizException.class)
    public RespBody<?> handleBusinessException(BizException e) {
    
    
        return ServerContext.getRespBody()
                .code(null != e.getCode() ? e.getCode() : HttpStatus.BAD_REQUEST.getValue())
                .msg(e.getMessage());
    }

    /**
     * 远程调用异常
     *
     * @param e
     * @return 自定义返回数据
     */
    @ResponseBody
    @ExceptionHandler(RemoteException.class)
    public RespBody<?> handleRemoteExceptionException(BizException e) {
    
    
        return ServerContext.getRespBody()
                .code(null != e.getCode() ? e.getCode() : HttpStatus.ERROR.getValue())
                .msg(e.getMessage());
    }

    /*
     * @param e       参数校验异常类型
     * @param request 请求参数
     * @return
     */
    @ResponseBody
    @ExceptionHandler({
    
    BindException.class, ConstraintViolationException.class, MethodArgumentNotValidException.class})
    public RespBody<Object> handleException(Exception e, HttpServletRequest request) {
    
    
        RespBody<Object> body = ServerContext.getRespBody();
        log.error("参数校验发生异常 当前请求 {} ,执行方法 {},异常信息 {}", request.getRequestURL().toString(), request.getMethod(), e);
        //参数校验异常
        StringBuffer errorMsg = new StringBuffer();
        if (!(e instanceof BindException) && !(e instanceof MethodArgumentNotValidException)) {
    
    
            for (ConstraintViolation cv : ((ConstraintViolationException) e).getConstraintViolations()) {
    
    
                Iterator<Path.Node> it = cv.getPropertyPath().iterator();
                Path.Node last = null;
                while (it.hasNext()) {
    
    
                    last = it.next();
                }
                errorMsg.append(last != null ? last.getName() : "").append(":").append(cv.getMessageTemplate()).append(";");
            }
        } else {
    
    
            List<ObjectError> allErrors;
            if (e instanceof BindException) {
    
    
                allErrors = ((BindException) e).getAllErrors();
            } else {
    
    
                allErrors = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
            }
            // 拼接错误信息
            for (ObjectError oe : allErrors) {
    
    
                if (oe instanceof FieldError) {
    
    
                    errorMsg.append(((FieldError) oe).getField()).append(":").append(oe.getDefaultMessage()).append(";");
                } else {
    
    
                    errorMsg.append(oe.getObjectName()).append(":").append(oe.getDefaultMessage()).append(";");
                }
            }
        }
        body.msg(errorMsg.toString()).code(HttpStatus.BAD_REQUEST.getValue());
        return body;
    }

    /**
     * 重新授权异常捕获
     *
     * @param e
     * @return
     */
    // @ResponseBody
    // @ExceptionHandler(UserRedirectRequiredException.class)
    // public void handleBusinessException(UserRedirectRequiredException e, HttpServletResponse response) throws IOException {
    
    
    //     response.sendRedirect(e.getRedirectUri());
    // }

    /**
     * 判断是否是ajax请求
     *
     * @param handlerMethod 处理方法
     * @return 是否
     */
    private boolean isAjax(HandlerMethod handlerMethod) {
    
    
        Method method = handlerMethod.getMethod();
        Class<?> clazz = method.getDeclaringClass();
        return clazz.isAnnotationPresent(RestController.class) || method.isAnnotationPresent(ResponseBody.class);
    }
}

分页信息:

@Data
public class Items<T> {
    
    
    /**
     * 数据
     */
    private Collection<T> rows = Collections.emptyList();
    /**
     * 总数
     */
    private int total;
}

分页查询:

@Data
public class PageInfo implements Serializable {
    
    

    private static final long serialVersionUID = 1L;

    /**
     * 数据开始位置
     */
    private Integer offset = 0;

    /**
     * 每页数量
     */
    private Integer limit = 10;

    /**
     * 升序 降序
     */
    private String sort;

    /**
     * 排序
     */
    private String order;

    public PageInfo() {
    
    
    }

    public PageInfo(Integer offset, Integer limit) {
    
    
        this.offset = offset;
        this.limit = limit;
    }
}

统一返回格式:

@Data
public class RespBody<T> {
    
    

    /**
     * 输出信息
     */
    private String msg;
    /**
     * 返回数据
     */
    private T body;
    /**
     * code状态码
     */
    private int code;

    /**
     * 默认构造成功信息
     */
    public RespBody() {
    
    
        this.code = HttpStatus.SUCCESS.getValue();
        this.msg = HttpStatus.SUCCESS.getMsg();
    }

    public RespBody(int code, String msg) {
    
    
        this.code = code;
        this.msg = msg;
    }

    public RespBody(int code, String msg, T body) {
    
    
        this.code = code;
        this.msg = msg;
        this.body = body;
    }

    public static <T> RespBody<T> success() {
    
    
        return new RespBody<>();
    }

    public static <T> RespBody<T> error(int code, String msg) {
    
    
        return new RespBody<>(code, msg);
    }

    public static <T> RespBody<T> error(String msg) {
    
    
        return new RespBody<>(HttpStatus.ERROR.getValue(), msg);
    }

    public RespBody<T> code(int code) {
    
    
        this.code = code;
        return this;
    }

    public RespBody<T> msg(String msg) {
    
    
        this.msg = msg;
        return this;
    }

    public RespBody<T> body(T body) {
    
    
        this.body = body;
        return this;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_44723773/article/details/131068560