1.自定义Spring MVC接受List参数
SpringMVC3.1引入了HandlerMethodArgumentResolver接口,spring调用该接口实现Controller的参数装配。HandlerMethodArgumentResolver实现类中会调用DataBinder,Converter等。
常用的该接口实现类有:
ServletModelAttributeMethodProcessor:实体类的组装用它实现。
RequestParamMethodArgumentResolver:基本数据类型如String用它实现。
在我学习过程中,发现对List类型的参数SpringMVC没有提供默认实现。我参照Spring的示例 通过实现 HandlerMethodArgumentResolver接口,实现对List参数的组装。
示例中用到的Model类:
- package com.weishubin.springmvc.model;
-
- public class User {
- private String name;
- private int age;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(name);
- sb.append("-");
- sb.append(age);
- return sb.toString();
- }
- }
注解类:
- package com.weishubin.springmvc.listargument;
-
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- @Target(ElementType.PARAMETER)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface ListAttribute {
-
- }
实现了HandlerMethodArgumentResolver接口的参数解析器:
- package com.weishubin.springmvc.listargument;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import org.springframework.beans.BeanWrapper;
- import org.springframework.beans.PropertyAccessorFactory;
- import org.springframework.core.MethodParameter;
- import org.springframework.web.bind.support.WebDataBinderFactory;
- import org.springframework.web.context.request.NativeWebRequest;
- import org.springframework.web.method.support.HandlerMethodArgumentResolver;
- import org.springframework.web.method.support.ModelAndViewContainer;
-
- import com.weishubin.springmvc.model.User;
-
- public class ListArgumentResolver implements HandlerMethodArgumentResolver {
-
- public boolean supportsParameter(MethodParameter parameter) {
-
- return parameter.getParameterAnnotation(ListAttribute.class) != null;
- }
-
- public Object resolveArgument(MethodParameter parameter,
- ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
- WebDataBinderFactory binderFactory) throws Exception {
- List<User> users = new ArrayList<User>();
- String[] names = webRequest.getParameterValues("name");
- String[] ages = webRequest.getParameterValues("age");
-
-
- for (int i = 0; i < names.length; i++) {
- User user = new User();
- BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(user);
-
- String name = names[i];
- String age = ages[i];
- beanWrapper.setPropertyValue("name", name);
- beanWrapper.setPropertyValue("age", age);
-
- users.add(user);
- }
- return users;
- }
-
- }
Controller类:
- package com.weishubin.springmvc.listargument;
-
- import java.util.List;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- import com.weishubin.springmvc.model.User;
-
- @Controller
- public class ListArgumentController {
-
- @ResponseBody
- @RequestMapping("/list")
- public String argumentResolver(@ListAttribute List<User> list) {
- StringBuilder b = new StringBuilder();
- for (User u : list) {
- b.append(u);
- b.append("<br/>");
- }
- return b.toString();
- }
- }
配置文件:
- <mvc:annotation-driven>
- <mvc:argument-resolvers>
- <bean class="com.weishubin.springmvc.listargument.ListArgumentResolver"/>
- </mvc:argument-resolvers>
- </mvc:annotation-driven>
2.对接受的参数进行Base64解密处理
1.自定义注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Description: <br/>
* Tsp请求,入参自动Base64转码注解
* @date 2016年4月8日 下午4:26:14
*
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TspRequestBase64 {
}
2.定义对使用注解的入参处理
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import com.alibaba.fastjson.JSONObject;
import com.xx.movie.confirmation.common.annotation.TspRequestBase64;
/**
* Description: <br/>
* Tsp服务,入参进行Base64自动转码
* @date 2016年4月8日 下午3:46:41
*
*/
public class TspRequestBase64Resolver implements HandlerMethodArgumentResolver {
private Charset defaultCharset = Charset.forName("UTF-8");
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(TspRequestBase64.class);
}
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
HttpInputMessage message = new ServletServerHttpRequest(request);
Charset charset = this.getContentCharset(message.getHeaders().getContentType());
String body = FileCopyUtils.copyToString(new InputStreamReader(request.getInputStream(), charset));
//如果是GET请求,body应该是空,重新获取
if (StringUtils.isEmpty(body)) {
body = request.getQueryString();
}
byte[] content = null;
if(body != null && body.length() > 0){
if (Base64.isBase64(body)) {
content = Base64.decodeBase64(body);
} else {
content = body.getBytes(charset);
}
}
return (content == null) ? null : JSONObject.parseObject(content, parameter.getParameterType());
}
//获取charset
public Charset getContentCharset(MediaType mediaType) {
if (mediaType != null && mediaType.getCharSet() != null) {
return mediaType.getCharSet();
} else {
return this.defaultCharset;
}
}
}
3.配置spring-mvc.xml文件
<!-- 启用spring mvc 注解 -->
<mvc:annotation-driven>
<mvc:argument-resolvers>
<!-- aop解析TspRequest注解 -->
<beans:bean
class="com.xx.movie.confirmation.common.util.TspRequestBase64Resolver"></beans:bean>
<beans:bean
class="com.xx.nfbird.web.argument.JsonMapperArgumentResolver"></beans:bean>
<!-- pagination -->
<beans:bean
class="com.xx.nfbird.web.argument.PaginationArgumentResolver"></beans:bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
4.Spring MVC中使用
@RequestMapping(value = "/order/take", method = RequestMethod.POST)
@ResponseJson(translate = true)
public SeqId orderOccupy(@TspRequestBase64 OrderOccupyRequestVo occupyVo) throws Exception {
解析:
传入的参数必须是Base64位加密之后的,在Spring MVC接受到参数后,回先进行参数的解码
3.使用Shiro+HanderMethodArgumentResolver在入参时,获取安全上下文
为@RequestMapping标注的方法扩展传入的参数。
以shiro为例,扩展一个标注,@CurrentUser,只要有这个标注,就可以在shiro的安全上下文中取出适当的对象直接从参数传入,request响应函数。
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
-
- @Documented
- @Target({ElementType.PARAMETER})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface CurrentUser {
- }
- @RequestMapping(value = "/test1")
- public @ResponseBody String test1(@CurrentUser Long userId) {
- return userId.toString();
- }
-
- @RequestMapping(value = "/test2")
- public @ResponseBody String test2(@CurrentUser UserDetails userDetails) {
- return userDetails.toString();
- }
- import java.lang.annotation.Annotation;
-
- import org.springframework.core.MethodParameter;
- import org.springframework.web.bind.support.WebDataBinderFactory;
- import org.springframework.web.context.request.NativeWebRequest;
- import org.springframework.web.method.support.HandlerMethodArgumentResolver;
- import org.springframework.web.method.support.ModelAndViewContainer;
-
- import com.github.yingzhuo.mycar2.annotation.CurrentUser;
- import com.github.yingzhuo.mycar2.security.SecurityUtils;
- import com.github.yingzhuo.mycar2.security.UserDetails;
-
- public class CurrentUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
-
- @Override
- public boolean supportsParameter(MethodParameter parameter) {
- Class<?> klass = parameter.getParameterType();
- if (klass.isAssignableFrom(UserDetails.class) || klass.isAssignableFrom(Long.class)) {
- Annotation[] as = parameter.getParameterAnnotations();
- for (Annotation a : as) {
- if (a.annotationType() == CurrentUser.class) {
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
- WebDataBinderFactory binderFactory) throws Exception {
-
- if ((SecurityUtils.isAuthenticated() || SecurityUtils.isRemembered()) == false) {
- return null;
- }
-
- Class<?> klass = parameter.getParameterType();
-
- UserDetails userDetails = SecurityUtils.getUserDetails();
-
- if (klass.isAssignableFrom(UserDetails.class)) {
- return SecurityUtils.getUserDetails();
- }
-
- if (klass.isAssignableFrom(Long.class)) {
- return userDetails != null ? userDetails.getId() : null;
- }
-
- return null;
- }
- }
最后,需要配置一下
- <mvc:annotation-driven>
- <mvc:argument-resolvers>
- <bean class="xxx.yyy.CurrentUserHandlerMethodArgumentResolver" />
- </mvc:argument-resolvers>
- </mvc:annotation-driven>