一、使用注解拦截用户登录状态
1.定义Login注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
}
2.定义拦截器
public class UserInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if(handler instanceof HandlerMethod) {
UserVO user = getUser(request);
UserContext.setUser(user);
HandlerMethod hm = (HandlerMethod) handler;
//拦截有@Login注解的方法,验证是否有用户登录
Login login = hm.getMethodAnnotation(Login.class);
String callback = request.getParameter("callback");
if(null != login) {
if(user == null) {
WebUtil.render(response,CodeMsg.SESSION_EXPIRE,callback);
return false;
}
}
}
return true;
}
private UserVO getUser(HttpServletRequest request) {
HttpSession session = request.getSession();
Object object = session.getAttribute("userId");
if(null != object) {
UserVO user = new UserVO();
user.setUserId(Long.parseLong(object.toString()));
return user;
}
return null;
}
我这里用了一个UserContext,目的是上下文临时存放用户数据,便于后面使用,ThreadLocal为线程安全。
public class UserContext {
private static ThreadLocal<UserVO> userHolder = new ThreadLocal<UserVO>();
public static void setUser(UserVO user) {
userHolder.set(user);
}
public static UserVO getUser() {
return userHolder.get();
}
}
还有一点需要注意,我们项目用了jsonp,所以在out.write的时候不要忘了callback。
public class WebUtil {
public static void render(HttpServletResponse response,CodeMsg cm,String callback) throws IOException {
response.setContentType("application/json;charset=utf-8");
OutputStream out = response.getOutputStream();
String str = JSON.toJSONString(Result.result(cm));
if(StringUtil.isNotEmpty(callback)) {
str = callback+"("+str+")";
}
out.write(str.getBytes("utf-8"));
out.flush();
out.close();
// TODO Auto-generated method stub
}
}
3.xml文件配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.cmedicine.core.interceptor.UserInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
因为我们用了<mvc:annotation-driven> ,所以拦截器不可以用bean的方式配置,会导致失效的情况。
4.使用
在需要用户登录的方法加上@Login注解,即可对用户登录状态校验
@Login
@RequestMapping(params = "method=test",produces={"application/json; charset=UTF-8"})
@ResponseBody
public Result test(String e) {
return Result.success();
}
二、自定义解析器
上面我们配置了用户状态拦截,并且把用户信息放到了ThreadLocal,下面我们就把它拿出来。
1.定义@LoginUser注解
/**
* 登录用户信息
* @author hanyuelei
*
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}
2.自定义解析器,实现HandlerMethodArgumentResolver 接口
/**
* 给controller带@LoginUser注解的参数userVo注入当前登录用户信息
* @author hanyuelei
*
*/
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 只有这里返回true ,才会执行resolveArgument
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
// TODO Auto-generated method stub
Class<?> clazz = parameter.getParameterType();
// return clazz == UserVO.class;
return parameter.getParameterType().isAssignableFrom(UserVO.class) && parameter.hasParameterAnnotation(LoginUser.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// TODO Auto-generated method stub
// HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
// HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
// String userId = request.getAttribute("userId").toString();
System.out.println("获取用户:"+UserContext.getUser());
//从UserContext获取用户
return UserContext.getUser();
}
}
3.配置xml,指定我们自定义的解析器,我们前面配置过 <mvc:annotation-driven>
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="com.cmedicine.core.interceptor.resolver.UserArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
4.使用,参数增加@LoginUser
@Login
@RequestMapping(params = "method=test",produces={"application/json; charset=UTF-8"})
@ResponseBody
public Result test(@LoginUser UserVO uservo) {
System.out.println("userId:"+uservo.getUserId());
return Result.success(uservo.getUserId());
}