ssm前后端分離--返回數據封裝、異常處理、跨域問題解決。


上一篇我寫的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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM