package com.company.project.configurer; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4; import com.company.project.core.Result; import com.company.project.core.ResultCode; import com.company.project.core.ServiceException; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Spring MVC 配置 */ @Configuration public class WebMvcConfigurer extends WebMvcConfigurerAdapter { private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class); @Value("${spring.profiles.active}") private String env;//当前激活的配置文件 //使用阿里 FastJson 作为JSON MessageConverter @Override public void configureMessageConverters(List> converters) { FastJsonHttpMessageConverter4 converter = new FastJsonHttpMessageConverter4(); FastJsonConfig config = new FastJsonConfig(); config.setSerializerFeatures(SerializerFeature.WriteMapNullValue,//保留空的字段 SerializerFeature.WriteNullStringAsEmpty,//String null -> "" SerializerFeature.WriteNullNumberAsZero);//Number null -> 0 converter.setFastJsonConfig(config); converter.setDefaultCharset(Charset.forName("UTF-8")); converters.add(converter); } //统一异常处理 @Override public void configureHandlerExceptionResolvers(List exceptionResolvers) { exceptionResolvers.add(new HandlerExceptionResolver() { public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) { Result result = new Result(); if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; if (e instanceof ServiceException) {//业务失败的异常,如“账号或密码错误” result.setCode(ResultCode.FAIL).setMessage(e.getMessage()); logger.info(e.getMessage()); } else { result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage("接口 [" + request.getRequestURI() + "] 内部错误,请联系管理员"); String message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s", request.getRequestURI(), handlerMethod.getBean().getClass().getName(), handlerMethod.getMethod().getName(), e.getMessage()); logger.error(message, e); } } else { if (e instanceof NoHandlerFoundException) { result.setCode(ResultCode.NOT_FOUND).setMessage("接口 [" + request.getRequestURI() + "] 不存在"); } else { result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage(e.getMessage()); logger.error(e.getMessage(), e); } } responseResult(response, result); return new ModelAndView(); } }); } //解决跨域问题 @Override public void addCorsMappings(CorsRegistry registry) { //registry.addMapping("/**"); } //添加拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { //接口签名认证拦截器,该签名认证比较简单,实际项目中建议使用Json Web Token代替。 if (!StringUtils.contains(env, "dev")) { //开发环境忽略签名认证 registry.addInterceptor(new HandlerInterceptorAdapter() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String sign = request.getParameter("sign"); //验证签名 if (StringUtils.isNotEmpty(sign) && validateSign(request, sign)) { return true; } else { logger.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap())); Result result = new Result(); result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败"); responseResult(response, result); return false; } } }); } } private void responseResult(HttpServletResponse response, Result result) { response.setCharacterEncoding("UTF-8"); response.setHeader("Content-type", "application/json;charset=UTF-8"); response.setStatus(200); try { response.getWriter().write(JSON.toJSONString(result)); } catch (IOException ex) { logger.error(ex.getMessage()); } } /** * 一个简单的签名认证,规则:请求参数按ASCII码排序后,拼接为a=value&b=value...这样的字符串后进行MD5 * * @param request * @param requestSign * @return */ private boolean validateSign(HttpServletRequest request, String requestSign) { List keys = new ArrayList(request.getParameterMap().keySet()); Collections.sort(keys); String linkString = ""; for (String key : keys) { if (!"sign".equals(key)) { linkString += key + "=" + request.getParameter(key) + "&"; } } if (StringUtils.isEmpty(linkString)) return false; linkString = linkString.substring(0, linkString.length() - 1); String key = "Potato";//自己修改 String sign = DigestUtils.md5Hex(linkString + key); return StringUtils.equals(sign, requestSign); } private String getIpAddress(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } // 如果是多级代理,那么取第一个ip为客户ip if (ip != null && ip.indexOf(",") != -1) { ip = ip.substring(0, ip.indexOf(",")).trim(); } return ip; } }