潘瑞峰的个人博客

springMVC自定义注解AOP以及请求响应参数格式

潘瑞峰 SpringMVC请求参数格式与返回数据格式annotationaspectaop自定义注解切面

Spring MVC 请求参数和返回参数的格式

1. 峰驼转下划线

在JAVA中,变量的命名方式一般为峰驼型(如userName),而在前端则是下划线方式(如user_name),springMVC提供了一种转换的适配

对dispacther的jackson进行配置

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
              <property name="messageConverters">
                     <list>
                            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                                <!-- 驼峰转下划线 -->
                                <property name="objectMapper">
                                    <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                                        <property name="propertyNamingStrategy">
                                             <bean class="com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy" />
                                        </property>
                                     </bean>
                                </property>
                                <property name="supportedMediaTypes">
                                    <list>
                                        <!-- <value>text/html;charset=UTF-8</value> -->
                                        <value>application/json; charset=UTF-8</value>
                                    </list>
                                </property>
                                <!-- 驼峰转下划线 -->
                            
                            </bean>
                            
                            <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
                     </list>
              </property>
       </bean>

对于返回的结果,会将后端的userName,转化为前端的user_name

2. formdata

后端接收formdata的时候,可以通过重命名来确定接收的变量在后端的名称,如下,前端传过来的user_name会被放到userName变量

@RequestParam(value = "user_Name", required = true) String userName

请求数据 formdata: user_name=xxxx

3. RequestBody接收json数据

除了formdata,一般的后台还接收json格式的数据

后端接收参数的方法如下(其中user有私有属性:id,userName,password,name,registerDate)

@RequestBody User u

请求参数

{
    "id": 1,
    "user_name": "dapan",
    "password": "123",
    "name": "dapan",
    "register_date": "1993-10-22"
  }

注意的是: 1) 在配置了峰驼转下划线后,请求体中的参数必须满足该规则(也就是user_name => userName);2) 参数只能少,不能多,少的置成null,多则出400错误

Spring MVC AOP 自定义注解

springMVC 提供AOP来拦截请求

在本文中,我们通过AOP来检查用户类型;用户类型分:普通用户和管理员

所以我们先定义一个annotation(如下)

@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.METHOD,ElementType.TYPE})  
@Documented  
//最高优先级  
@Order(Ordered.HIGHEST_PRECEDENCE)  
public @interface CheckUser {
    UserType type() default UserType.User; //UserType 是一个含有User和Admin的枚举类型

}

然后定义该annotation对应的切片(如下)

//before: 函数执行前所需要的操作
@Before("@annotation(com.demo.annotation.CheckUser) && (args(request,response,..) || args(..,request,response))") 
     public void beforeExec(JoinPoint joinPoint,HttpServletRequest request,HttpServletResponse response) {
         MethodSignature signature = (MethodSignature) joinPoint.getSignature();  
         Method method = signature.getMethod();  
         Class<?> classz = joinPoint.getTarget().getClass();
         
         CheckUser checkUser = getCheckUser(method,classz);//通过反射,获取注解里面UserType的值
         

         String token = request.getParameter("token");//获取请求体里面的令牌
         User user =  SessionManager.getSession(token);//系统中存储<令牌,用户>键值对的管理器
         if (user != null) {
             //在这里可以检查用户类型,是否为注解所要求的用户类型
         } else {
             //用户令牌无效的情况下,将response截断,并且返回{"code":1}(如果不截断,则会根据执行controller后,返回controller定义的类型)
             try {
                 response.reset();
                 response.setStatus(200);
                 response.setContentType("application/json;charset=UTF-8");
                 OutputStream out = response.getOutputStream();
                 out.write("{\"code\":1}".getBytes());
                 out.flush();
                 out.close();

             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
     }

对应的控制器如下,可以看出当调用getUserList接口的时候,首先会根据自定义的注解CheckUser,去执行相应的aspcet中的(beforeExec),在aspect中检查用户的权限,根据用户权限来提前截断,或者继续执行

    @CheckUser(type=UserType.Admin)
    @RequestMapping(value="getUserList", method = RequestMethod.GET)
    @ResponseBody
    public DataWrapper<list<User>> getUserList(
            HttpServletRequest request,
            HttpServletResponse response,
            @RequestParam(value = "token",required = true) String token
            ) {
        
        return  userService.getUserList(token);
    }

备注: 根据controller里面@CheckUser可知,在切片中,变量checkUser的值是UserType.Admin

代码在我的git上 github

潘瑞峰
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。