一、使用註解攔截用戶登錄狀態
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());
}