上一篇我写的IDEA+maven搭建前后端分离ssm环境将基本的ssm前后端分离的架子搭起来了,不过还是存在一些问题的。比如:返回的数据未进行分装(有bug),未对常用异常如400、404、405、500进行捕获,跨域问题。本文将对这些问题进行解决。
问题一:返回数据的分装
1、在util包中创建OutputJson对返回的数据进行统一约束
package com.hsy.sms.util;
import java.io.Serializable;
import com.alibaba.fastjson.JSON;
public class OutputJson implements Serializable {
/**
* 返回客户端统一格式,包括状态码,提示信息,以及业务数据
*/
private static final long serialVersionUID = 1L;
//状态码
private int code;
//必要的提示信息
private String msg;
//业务数据
private Object data;
public OutputJson(int code,String msg){
this.code = code;
this.msg = msg;
// this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String toString(){
// if(null == this.data){
// this.setData(new Object());
// }
return JSON.toJSONString(this);
}
}
package com.hsy.sms.util;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ReturnFormat {
private static Map<String,String> messageMap =new HashMap();
//初始化状态码与文字说明
static {
messageMap.put("400", "Bad Request!");
messageMap.put("401", "NotAuthorization");
messageMap.put("404", "Resource is not available");
messageMap.put("405", "Method Not Allowed");
messageMap.put("406", "Not Acceptable");
messageMap.put("500", "Internal Server Error");
}
//出现异常时调用
public static String retParam(int code) {
OutputJson json = new OutputJson(code, messageMap.get(String.valueOf(code)));
return json.toString();
}
//正常时调用
public static String retData(Object data){
OutputJson json = new OutputJson(200, "ok!");
json.setData(data);
return json.toString();
}
}
3、正常程序中对返回封装类的使用
@RequestMapping(value = "/login", method = RequestMethod.POST, consumes="application/x-www-form-urlencoded")
@ResponseBody
public Object selectUserInfo(@RequestParam(value="uid") int uid,@RequestParam(value="password") String pwd_id) throws Exception {
User user = userService.getUserInfoById(uid);
if(user == null ){
return ReturnFormat.retData("用户不存在");
}else if(user.getPwd_id().equals(pwd_id)){
/**
* 将密码隐藏
* 将密码设置为null
* com.alibaba.fastjson.JSON.toJSONString()方法将自动不返回为空的字段
*/
user.setPwd_id(null);
return ReturnFormat.retData(user);
}else{
return ReturnFormat.retData("密码错误");
}
}
4、编写异常增强类RestExceptionHandler
package com.hsy.sms.handler;
import com.hsy.sms.util.ReturnFormat;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.NoHandlerFoundException;
import java.io.IOException;
@ControllerAdvice
public class RestExceptionHandler {
//400错误
@ExceptionHandler({HttpMessageNotReadableException.class})
@ResponseBody
public String requestNotReadable(HttpMessageNotReadableException ex){
System.out.println("400..requestNotReadable");
ex.printStackTrace();
return ReturnFormat.retParam(400 );
}
//400错误
@ExceptionHandler({TypeMismatchException.class})
@ResponseBody
public String requestTypeMismatch(TypeMismatchException ex){
System.out.println("400..TypeMismatchException");
ex.printStackTrace();
return ReturnFormat.retParam(400 );
}
//400错误
@ExceptionHandler({MissingServletRequestParameterException.class})
@ResponseBody
public String requestMissingServletRequest(MissingServletRequestParameterException ex){
System.out.println("400..MissingServletRequest");
ex.printStackTrace();
return ReturnFormat.retParam(400 );
}
//405错误
@ExceptionHandler({HttpRequestMethodNotSupportedException.class})
@ResponseBody
public String request405(){
System.out.println("405...");
return ReturnFormat.retParam(405 );
}
//406错误
@ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
@ResponseBody
public String request406(){
System.out.println("404...");
return ReturnFormat.retParam(406 );
}
//500错误
@ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
@ResponseBody
public String server500(RuntimeException runtimeException){
System.out.println("500...");
return ReturnFormat.retParam(406 );
}
}
对于全局异常的处理笔者也百度也很多,试过很多方法比如:@CrossOrigin注解等等,但都不好使。皇天不负有心人,终于在一篇<a href="https://www.cnblogs.com/nosqlcoco/p/5562107.html">springmvc 通过异常增强返回给客户端统一格式</a>博客中找到了解决方法。这时我耳边响起了一句话:“问题一定会解决的,如果你还没有解决说明还没到最后”。不过还有一个小bug(返回异常为中文时会出现???的乱码。
补充:ssm前后端分离中对于404异常的捕获
在全局异常捕获中加入
/**
* me 404-NOT_FOUND
* @param e
* @return
*/
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseBody
public String handlerNotFoundException(NoHandlerFoundException e)
{
System.out.println("请求的资源不可用");
return ReturnFormat.retParam(404);
}
在web.xml--servlet中加入
<!--因为DispatcherServlet源码中对于throwExceptionIfNoHandlerFound 默认是 false 我们需要在初始化DispatcherServlet时将参数值更改为true.-->
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
问题三:跨域问题
在前后端分离过程必然会遇到跨域问题具体原因感兴趣的可以移步<a href="https://www.cnblogs.com/Juaoie/p/9786313.html">ajax中的json和jsonp详解</a><a href="https://www.cnblogs.com/Juaoie/p/11692819.html">浏览器的同源策略和跨域详解(内含故事解析</a>这里我就不说这段离奇曲折的解决过去与故事了。话不多说直接上解决方法
1、实现Filter接口设置响应头
package com.hsy.sms.util;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
public class SimpleCORSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
//httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,access_token,refresh_token");
httpResponse.setHeader("Access-Control-Allow-Methods", "GET, PUT, DELETE, POST");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Max-Age", "0");
httpResponse.setContentType("text/html;charset=UTF-8");
httpResponse.setHeader("XDomainRequestAllowed","1");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
2、在web.xml中加入自定义的过滤器
<!-- 跨域过滤 -->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>com.hsy.sms.util.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
|