上一篇我寫的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);
}
}
2、創建ReturnFormat定義全局異常及方法供調用
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>