• 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>
    
  • 相关阅读:
    sscanf()
    分享:Python字符编码详解
    STL priority_queue使用
    google maps 控件controller
    Google Maps Overlays叠加层
    java JDBC配置和使用
    转:总结java的interface和abstract class
    java 多线程 之 生产者和消费者
    一个简单的marker和infowindow
    java Nested Classes
  • 原文地址:https://www.cnblogs.com/shaoyu/p/11701242.html
Copyright © 2020-2023  润新知