此篇文章介绍一些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;
}
}