问题流程描述
前端
前端页面填写账号和密码,并使用post请求发送给后端.
controller控制器
控制器根据前端发过来的请求的url,确定要执行的业务是login。并根据动态代理创建service层的动态代理实现业务层login的工作。
public class UserController extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//模板模式
System.out.println("进入到用户控制器");
String path = request.getServletPath();
if("/settings/user/login.do".equals(path)){
login(request, response);
}
}
private void login(HttpServletRequest request, HttpServletResponse response) {
System.out.println("进入到验证登录操作");
//在请求与中获得账号和密码
String loginAct=request.getParameter("loginAct");
String loginPwd = request.getParameter("loginPwd");
System.out.println(loginAct+" "+loginPwd);
//将密码进行MD5加密
loginPwd = MD5Util.getMD5(loginPwd);
String ip = request.getRemoteAddr();
System.out.println("-----------ip");
//未来业务层的开发,统一使用代理类形态的接口对象
UserService us =(UserService) ServiceFactory.getService(new UserServiceImpl());
try{
User user = us.login(loginAct, loginPwd, ip);
//向session中传入user对象
request.getSession().setAttribute("user", user);
//如果程序能走到这里说明已经拿回了正确的user,则直接传入success
PrintJson.printJsonFlag(response,true);
}catch (Exception e){
e.printStackTrace();
//如果程序走到了这里就说明我们的程序没有在数据库中拿到对应的对象,说明登陆失败
//我们需要传入失败的原因,也就是我们抛出的异常的msg
String msg = e.getMessage();
Map<String, Object> map=new HashMap<>();
map.put("success", false);
map.put("msg", msg);
PrintJson.printJsonObj(response, map);
}
}
}
service层
service层中使用login函数在dao底层中查询数据库,筛选匹配的涌弧信息。因为密码是故意输错的,所以dao层没有查询到用户.dao层返回的对象是一个空值。空值在service层中的逻辑判断出抛出自定异常,提示账号密码错误。但是最终却能正常的登录产生跳转。
@Override
public User login(String loginAct, String loginPwd, String ip) throws LoginException {
Map<String, String> map = new HashMap<>();
map.put("loginAct", loginAct);
map.put("loginPwd", loginPwd);
User user =userDao.login(map);
if(user == null){
throw new LoginException("账号密码错误");
}
//如果程序运行到此处说明账户密码是正确豆的,则还需要验证以下三项
//1、验证失效时间
String expireTime = user.getExpireTime();
System.out.println(expireTime);
String currentTime = DateTimeUtil.getSysTime();
if(expireTime.compareTo(currentTime) < 0){
throw new LoginException("账号已失效");
}
//判断账号状态
String lockState = user.getLockState();
if("0".equals(lockState)){
throw new LoginException("账号已锁定");
}
// //判断IP地址 0:0:0:0:0:0:0:1
// String allowIp = user.getAllowIps();
// System.out.println(allowIp);
// System.out.println(ip);
//
// if(!allowIp.contains(ip)){
// throw new LoginException("ip不允许");
// }
return user;
}
动态代理
public class TransactionInvocationHandler implements InvocationHandler {
private Object target;
public TransactionInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = null;
Object obj = null;
try{
sqlSession = SqlSessionUtil.getSqlSession();
//实现目标类的方法
obj = method.invoke(target, args);
//做功能增强,提交事务
sqlSession.commit();
}catch(Exception e){
sqlSession.rollback();
e.printStackTrace();
//注意这里加入这个是为了防止目标类的异常被代理类捕获,所以需要再一次抛出已捕捉到的异常
// throw e.getCause();
}finally {
SqlSessionUtil.myClose(sqlSession);
}
return obj;
}
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this );
}
问题分析
原因是我在controller层中为userService实现了动态代理的机制。该代理类调用login函数,在login函数中抛出了密码错误的异常,但是目标类的异常在InovactionHandeller中的invoke方法上捕获了,导致没有异常发生,所以在最后认为是登陆成功。
解决办法
在InvocationHandellor中的invoke方法中的catch代码块中将捕捉到的异常再次抛出。