Spring 使用Postman实现 mvc 与 Json数据交互 与 统一异常处理
一:使用Postman实现 mvc 与 Json数据交互
修改web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!-- 三、编码过滤器--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 一、spring mvc--> <servlet> <servlet-name>app1</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-web.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app1</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
加入spring-web.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 1.组件扫描--> <context:component-scan base-package="com.cc.mvc.**"></context:component-scan> <!-- 2、注解适配器和映射器--> <mvc:annotation-driven/> <!--3、视图解析器--> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <!-- 4、文件上传解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置上传文件的最大尺寸为5MB --> <property name="maxUploadSize"> <value>5242880</value> </property> </bean> <!-- 5、静态资源映射 mapping : 客户端浏览器路径 images/1.jpg images/product/2.jpg location: 项目根据路径的下的指定目录下 /WEB-INF/images/1.jpg /WEB-INF/images/2.jpg --> <mvc:resources mapping="/images/**" location="/WEB-INF/images/"></mvc:resources> </beans>
建立User实体类
public class User { private String id; @JsonIgnore private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } }
建立一个ResopsonseStatus枚举类,用来传递响应的结果
package com.cc.mvc.constants; public enum ResopsonseStatus { OK("200","请求成功!"), AUTHOR_ERROR("1001","接口认证失败"), INTENAL_ERROR("1003","程序内部错误"), AUTHOR_OUTTIME("1002","认证过期"); private String code; private String msg; ResopsonseStatus(String code, String msg) { this.code = code; this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
建立ServerResponse实体类,用于反回响应后的结果
package com.cc.mvc.response; import com.cc.mvc.constants.ResopsonseStatus; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.io.Serializable; @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) //@JsonInclude(JsonInclude.Include.NON_NULL) public class ServerResponse<T> implements Serializable{ @JsonIgnore private String code;/*业务响应嘛*/ @JsonIgnore private String msg;/*相应的信息*/ // private Object obj;/*相应的数据,不推荐*/ private T data;/*相应数据,推荐*/ private ServerResponse(String code,String msg,T data) { this.code=code; this.msg=msg; this.data=data; } /*成功的响应*/ public static ServerResponse ok(Object t){ return new ServerResponse(ResopsonseStatus.OK.getCode(),ResopsonseStatus.OK.getMsg(),t); } /*失败的响应,固定错误信息*/ public static ServerResponse error(Object t){ return new ServerResponse(ResopsonseStatus.INTENAL_ERROR.getCode(), ResopsonseStatus.INTENAL_ERROR.getMsg(),t); } /*失败的响应,自定义错误信息*/ public static ServerResponse errorMsg(String msg){ return new ServerResponse(ResopsonseStatus.INTENAL_ERROR.getCode(), msg,null); } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
注意:这里@JsonIgnore 是代表着,你需要显示到前端的就不加这个注解,不需要显示到前端的就加上这个注解
写Controller测试,这是使用json对象字符串的方式传递过去,我们运行一下,先将Tomcat跑起来
@Controller public class TestController { @Autowired private UserService userService; @RequestMapping(value = "/test", produces="application/json;charset=UTF-8") @ResponseBody public String test(HttpServletResponse response){ // response.setContentType("application/json;charset=gbk"); //return "index"; return "{\"name\":\"二狗子\",\"age\":12,\"sex\":\"男\",\"address\":\"马栏山\"}"; } }
随后我们将Postman启动,并模拟前端发送请求到后台,获取返回值
接下来使用json对象数组的方式传递过去,在Controller加入测试方法
@RequestMapping("/json2") @ResponseBody //spring mvc默认采用json序列化框架:fastJson ,Gson , Jackson框架(默认) public User getUser(){ User user = new User(); user.setId("2"); user.setName("二狗子"); return user; }
在Postman里更改成下面这样,然后访问
这个User对象就返回过来了。但是name没返回过来,原因就是在建立User实体类表中加入了@JsonIgnore,所有才只显示了一个id过来,去掉就一起返回了
使用Postman模拟前端输入用户ID账号,并返回用户id到前端,在Controller加入测试方法
@ResponseBody @RequestMapping(value = "/add_user",method = RequestMethod.POST) public ServerResponse<User> addUser(@RequestBody User user){ System.out.println("----进入adduser----"+user); return ServerResponse.ok(user); }
使用Postman访问
注意这里一定要加上这个Content-Type
二,实现统一异常处理
web开发的三层架构,既:web层,service层,dao层 每一层都可能抛出我们自己定义业务异常:登录异常,请求异常,认证失败异常,如果在每一层 去处理处理这些异常,这个代码冗余,可用性不高,入侵到业务代码。spring mvc中可以对异常 进行统一处理:
DispatchServlet(老大)
web层 ----往spring mvc抛
service层 ---往web层抛出
dao层 --往service抛出
spring mvc如何进行统一异常处理:日志记录,发短信/发邮件,返回一些友好并安全信息给前端。
第一方式:HandlerExceptionResolver 异常处理器
1)返回值只能是ModelAndView 不适合前后端分离的项目,不推荐
package com.cc.mvc.exception; /* * 自定义异常处理器 * * */ import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //@Component public class MyHandlerExceptionResolver implements HandlerExceptionResolver{ @Nullable @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, @Nullable Object o, Exception e) { ModelAndView mv = new ModelAndView(); System.out.println("---MyHandlerExceptionResolver---"+e); mv.setViewName("error"); return mv; } }
方式二:@ControllerAdvice + @HandlerException 代理模式来解决(推荐)
1)可以返回ModelAndView也可以返回Json字符串
写入自定义异常类
package com.cc.mvc.exception; import com.cc.mvc.response.ServerResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @ControllerAdvice public class MyExceptionAdvice { @ExceptionHandler @ResponseBody public ServerResponse handlerOrderException(OrderException e){ System.out.println("----下订单过程中出错了...handlerOrderException---"); /* * 1,写日志 * 2,发送短信给开发人员 * 3,发送邮件通知其他部门负责人 * */ return ServerResponse.error("订单异常,msg"+e.toString()); } @ExceptionHandler(ArithmeticException.class) @ResponseBody public ServerResponse handlerArithException(ArithmeticException e){ System.out.println("----程序内部中出错了...handlerArithException---"); /* * 1,写日志 * 2,发送短信给开发人员 * 3,发送邮件通知其他部门负责人 * */ return ServerResponse.error("非业务异常:"+e.getMessage()); } }
写入第二个自定义异常类
package com.cc.mvc.exception; public class OrderException extends RuntimeException { public OrderException(String messges){ super(messges); } }
写入UserService接口
package com.cc.mvc.service; public interface UserService { void testEx() throws Exception; }
实现实体类中的方法
package com.cc.mvc.service.impl; import com.cc.mvc.service.UserService; import org.springframework.stereotype.Controller; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Override public void testEx() throws Exception { int a =10/0; } }
在Controller中加入测试方法
@RequestMapping("/exception01") @ResponseBody public String exception01(int num) throws Exception{ if (num==2){ throw new OrderException("订单出错"); }else if(num ==1){ int a =10/0; } userService.testEx(); //业务处理 return "success"; }
结果为下:
这里显示的只要不是等于2,就是非业务异常,如果需要修改等于2的订单异常返回的信息,可以在后台加上订单的枚举类
package com.cc.mvc.constants; public enum OrderStatus {
//跟上面自定义枚举类一样的
}