很多情况下,需要通过外部方法获取业务特定的公共的实例信息,例如在集成用户信息时,无状态协议下从缓存中获取用户认证信息等等,这里介绍一种自定义注解方式获取用户认证信息,这样在集成用户信息时,只要在web请求上使用一个注解就能获取.示例如下:
1:定义一个注解
import java.lang.annotation.*; /** * 从token获取用户Java对象注解类. * * @author Hohn */ @Documented @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface Token4User { //需要转换的类 // Class<?> requireClass(); }2:定义一个类,.实现springframework的 HandlerMethodArgumentResolver方法,这里要封装自己解析对应的实例参数方法,这里需要注意的是在获取需要的实例信息时应该抛出一个要自定义一个异常,避免参数解析器方法出现业务异常或获取不到实例时告诉程序,否则在web请求上使用注解出现异常导致程序挂断.
import com.ahies.common.exception.ItsmUnauthorizedException; import com.ahies.stater.redis.service.StringRedisServiceImpl; import com.google.gson.Gson; import org.apache.commons.lang.StringUtils; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; 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 javax.servlet.http.HttpServletRequest; import java.util.Map;
/** * 用于方法参数上加Token4User标签获取当前登录用户的信息. * <p> * * @author Hohn */ @Component public class UserBeanArgumentResolver implements HandlerMethodArgumentResolver { private static final String USER_TOKEN = "Token"; /** * =======用户id===================================================== */ private static final String USER_ID = "id"; /** * =======用户姓名===================================================== */ private static final String USER_NAME = "userName"; /** * =======登录id===================================================== */ private static final String USER_LOGIN_NAME = "loginName"; /** * 过滤出符合条件的参数,这里指的是加了 Token4User 注解的参数 * * @param parameter * @return */ @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(Token4User.class); } @Override public UserLoginInfo resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); //从请求头中获取用户json //从srping容器中注入bean [HandlerMethodArgumentResolver没有被spring实例化的对象,不能被IoC容器管理, 使用@Autowired注解没有配置required=false的情况下spring发现没有该对象会直接抛出Exception] StringRedisServiceImpl redisService = SpringContextUtils.getBean(StringRedisServiceImpl.class); String token = servletRequest.getHeader(USER_TOKEN); if (StringUtils.isBlank(token)) { token = servletRequest.getParameter(USER_TOKEN); } if (StringUtils.isBlank(token)) {//解析异常抛出自定义异常 throw new ItsmUnauthorizedException("请先授权登录,"); } String userJson = null; try { //从缓存中获取用户信息 userJson = redisService.get(token); } catch (Exception e) { e.printStackTrace(); } if (StringUtils.isBlank(userJson)) {//解析异常抛出自定义异常 throw new ItsmUnauthorizedException("请先授权登录"); } if (StringUtils.isNotEmpty(userJson)) { //字符串转json Map对象 Gson gs = new Gson(); try { Map<String, Object> map = gs.fromJson(userJson, Map.class); UserLoginInfo userLoginInfo = new UserLoginInfo(); if (map != null && map.size() > 0) { //设置id userLoginInfo.setId((String) map.get(USER_ID)); //设置token userLoginInfo.setToken(token); //设置登录id userLoginInfo.setLoginName((String) map.get(USER_LOGIN_NAME)); //设置姓名 userLoginInfo.setUserName((String) map.get(USER_NAME)); return userLoginInfo; } } catch (Exception e) { e.printStackTrace(); } } return null; } }
3.自定义异常类
/** * * 自定义异常处理类 */ public class ItsmUnauthorizedException extends RuntimeException{ private static final long serialVersionUID = 1L; public ItsmUnauthorizedException(String message) { super(message); } }
4.全局异常捕获类
import com.ahies.common.exception.ItsmUnauthorizedException; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.context.MessageSource; import org.springframework.http.HttpStatus; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; import java.util.Map; @ControllerAdvice public class ControllerSetup { @InitBinder public void initBinder(WebDataBinder binder){ StringTrimmerEditor stringTrimmerEditor=new StringTrimmerEditor(true); binder.registerCustomEditor(String.class,stringTrimmerEditor); } private static Logger log = LoggerFactory.getLogger(ControllerSetup.class); /** * 处理org.springframework.validation.Validator、org.hibernate.validator、javax.validation错误. * * @param request 请求. * @param bindException bindException. * @return Map. * @throws Exception */ @ExceptionHandler(value = BindException.class) @ResponseBody public Map<String, Object> jsonErrorHandler(HttpServletRequest request, BindException bindException) throws Exception { Map<String, Object> map = Maps.newHashMapWithExpectedSize(2); List<FieldError> errors = bindException.getBindingResult().getFieldErrors(); List<Map<String, String>> messageList = Lists.newArrayListWithExpectedSize(errors.size()); for(int i = 0, size = errors.size(); i < size; i++) { // 字段名称 - 提示信息. Map<String, String> fieldMap = Maps.newHashMapWithExpectedSize(2); FieldError fieldError = errors.get(i); fieldMap.put("field", fieldError.getField()); fieldMap.put("prompt", fieldError.getDefaultMessage()); messageList.add(fieldMap); } map.put("status", HttpStatus.BAD_REQUEST.value()); map.put("message", messageList); return map; } @ExceptionHandler(value = ItsmUnauthorizedException.class) @ResponseBody public Map<String, Object> jsonErrorHandler(ItsmUnauthorizedException e) throws Exception { log.info("系统异常", e); Map<String, Object> map = Maps.newHashMapWithExpectedSize(2); map.put("status", HttpStatus.FORBIDDEN.value()); map.put("message", e.getMessage()); return map; } @ExceptionHandler(value = Exception.class) @ResponseBody public Map<String, Object> jsonErrorHandler(HttpServletRequest request, Exception e) throws Exception { log.info("系统异常", e); Map<String, Object> map = Maps.newHashMapWithExpectedSize(2); map.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value()); map.put("message", e.getMessage()); return map; } }
注册自定义参数解析器
import com.ahies.common.pojo.UserBeanArgumentResolver; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import java.util.List; @Configuration public class WebMvcConfigurerConfigure extends WebMvcConfigurerAdapter { //实例化用户信息参数注解类 @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new UserBeanArgumentResolver()); super.addArgumentResolvers(argumentResolvers); } }
业务中有时需要将获取的参数再次封装,如再次获取会消耗系统大量内存或不必要的服务调用,此时,可以把参数设置到回话的上下文中:
RequestContextHolder.getRequestAttributes().setAttribute("User",userBean, RequestAttributes.SCOPE_REQUEST);//第三个参数设置参数在回话中的位置
Object user = RequestContextHolder.getRequestAttributes().getAttribute("User", RequestAttributes.SCOPE_REQUEST);
set方法第三个参数用来指定参数保存在上下文中的位置:
/**
* Constant that indicates request scope.
*/
int SCOPE_REQUEST = 0;
/**
* Constant that indicates session scope.
* <p>This preferably refers to a locally isolated session, if such
* a distinction is available (for example, in a Portlet environment).
* Else, it simply refers to the common session.
*/
int SCOPE_SESSION = 1;
/**
* Constant that indicates global session scope.
* <p>This explicitly refers to a globally shared session, if such
* a distinction is available (for example, in a Portlet environment).
* Else, it simply refers to the common session.
*/
int SCOPE_GLOBAL_SESSION = 2;
附类似的转载博文:
http://blog.csdn.net/u010187242/article/details/73647670