'); } '); } CRM项目SSM框架构建(二) | Journey to paradise

CRM项目SSM框架构建(二)


完成业务:

  • 首页功能
  • 用户登录
  • 安全退出
  • 登录验证

最终效果:

首页功能

需求分析

用户访问项目首页,首先进入登录页面。

时序&流程

** 前端要先访问首页index.jsp,再跳转到登录页面login.jsp,但页面资源都WEB-INF中不能直接访问,只能通过代码访问,通过Controller层请求页面,所以要在后端要做两件事,先根据用户输入跳转到首页,再根据首页请求跳转到登录页面。

Tomcat的web.xml配置在标签中规定了启动要显示的页面为首页

Controller层

IndexController

@Controller
public class IndexController {
    /*
        理论上,给Controller方法分配请求url:http://127.0.0.1:8080/crm/
        为了简便,协议://ip:port/应用名称必须省去,用/代表应用根目录下的/
     */
    @RequestMapping("/")
    public String index(){
        //请求转发
        return "index";
    }
}

UserController

接收到settings/qx/user/toLogin.do请求,跳转到login.jsp

@Controller
public class UserController {
    /**
     * url要和controller方法处理完请求之后,响应信息返回的页面的资源目录保持一致
     */
    @RequestMapping("/settings/qx/user/toLogin.do")
    public String toLogin(){
        //请求转发到登录页面
        return "settings/qx/user/login";
    }
}

前端页面

index.jsp

​ 在浏览器中输入settings/qx/user/toLogin.do以通过UserController访问login.jsp


    

用户登录

需求分析

用户在登录页面,输入用户名和密码,点击”登录”按钮或者回车,完成用户登录的功能.

  • 用户名和密码不能为空

  • 用户名或者密码错误,用户已过期,用户状态被锁定,ip受限 都不能登录成功

  • 登录成功之后,所有业务页面显示当前用户的名称

  • 实现10天记住密码

  • 登录成功之后,跳转到业务主页面

  • 登录失败,页面不跳转,提示信息

时序&流程

Mapper层

UserMapper.java

​ 创建查询封装好的用户名和密码的方法

User selectUserByLoginActAndPwd(Map<String,Object> map);

UserMapper.xml

​ 编写tbl_user表查询语句,查询与用户名和密码对应的用户的所有信息

<select id="selectUserByLoginActAndPwd" parameterType="map" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from tbl_user
    where login_act=#&#123;loginAct&#125; and login_pwd=#&#123;loginPwd&#125;
</select>

Service层

UserService.java

​ 创建查询用户的服务

User queryUserByLoginActAndPwd(Map<String, Object> map);

UserServiceImpl.java

​ 调用userMapper中的selectUserByLoginActAndPwd方法实现UserService接口中的queryUserByLoginActAndPwd服务

@Autowired
private UserMapper userMapper;

@Override
public User queryUserByLoginActAndPwd(Map<String, Object> map) &#123;
    return userMapper.selectUserByLoginActAndPwd(map);
&#125;

Controller层

UserController.java

@RequestMapping("/settings/qx/user/login.do")
public @ResponseBody Object login(String loginAct, String loginPwd, String isRemPwd, HttpServletRequest request, HttpServletResponse response, HttpSession session) &#123;
    //封装参数
    Map<String,Object> map = new HashMap<>();
    map.put("loginAct",loginAct);
    map.put("loginPwd",loginPwd);

    //调用service层方法,查询用户
    User user = userService.queryUserByLoginActAndPwd(map);

    //根据查询结果,生成响应信息
    ReturnObject returnObject = new ReturnObject();
    if (user == null) &#123;
        //登录失败,用户名或者密码错误
        returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
        returnObject.setMessage("用户名或者密码错误");
    &#125;else &#123;//进一步判断账号是否合法
        //user.getExpireTime()   //2019-10-20
        //        new Date()     //2020-09-10
        if (DateUtils.formateDateTime(new Date()).compareTo(user.getExpireTime()) > 0) &#123;
            //登录失败,账号已过期
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
            returnObject.setMessage("账号已过期");
        &#125; else if ("0".equals(user.getLockState())) &#123;
            //登录失败,状态被锁定
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
            returnObject.setMessage("状态被锁定");
        &#125; else if (!user.getAllowIps().contains(request.getRemoteAddr())) &#123;
            //登录失败,ip受限
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
            returnObject.setMessage("ip受限");
        &#125; else &#123;
            //登录成功
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);

            //把user加入session
            session.setAttribute(Contants.SESSION_USER, user);

            Cookie c1=new Cookie("loginAct",user.getLoginAct());
            Cookie c2=new Cookie("loginPwd",user.getLoginPwd());
            if("true".equals(isRemPwd))&#123;
                //如果需要记住密码,则往外写cookied
                c1.setMaxAge(10*24*60*60);
                c2.setMaxAge(10*24*60*60);
            &#125;else&#123;
                //把没有过期cookie删除
                c1.setMaxAge(0);
                c2.setMaxAge(0);
            &#125;
            response.addCookie(c1);
            response.addCookie(c2);
        &#125;
    &#125;
    return returnObject;
&#125;

WorkbenchIndexController.java

@RequestMapping("/workbench/index.do")
public String index()&#123;
    //跳转到业务主页面
    return "workbench/index";
&#125;

前端页面

login.jsp

在入口函数添加事件


安全退出

需求分析

​ 用户在任意的业务页面,点击”退出”按钮,弹出确认退出的模态窗口;用户在确认退出的模态窗口,点击”确定”按钮,完成安全退出的功能

  • 安全退出,清空cookie,销毁session
  • 退出完成,跳转到首页

时序&流程

Controller层

UserController

@RequestMapping("/settings/qx/user/logout.do")
public String logout(HttpServletResponse response, HttpSession session)&#123;
    //清空cookie
    Cookie c1=new Cookie("loginAct","1");
    c1.setMaxAge(0);
    response.addCookie(c1);
    Cookie c2=new Cookie("loginPwd","1");
    c2.setMaxAge(0);
    response.addCookie(c2);
    //销毁session
    session.invalidate();
    //跳转到首页 重定向
    return "redirect:/";
&#125;

前端页面

index.jsp

  1. 给确认退出按钮加id选择器

    
    
  2. 在入口函数给“确定”按钮添加单击事件

    //给“确定”按钮添加单击事件
    $("#logoutBtn").click(function () &#123;
    //发送同步请求
    window.location.href="settings/qx/user/logout.do";
    &#125;);
    

登录验证

需求分析

​ 用户访问任何业务资源,都需要进行登录验证.

  • ​ 只有登录成功的用户才能访问业务资源
  • ​ 没有登录成功的用户访问业务资源,跳转到登录页面

配置拦截器

  1. 登录验证拦截器类LoginInterceptor.java

        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception &#123;
            //如果用户没有登录成功,则跳转到登录页面
            HttpSession session=httpServletRequest.getSession();
            User user=(User) session.getAttribute(Contants.SESSION_USER);
            if(user==null)&#123;
                httpServletResponse.sendRedirect(httpServletRequest.getContextPath());//重定向时,url必须加项目的名称
                return false;
            &#125;
            return true;
        &#125;
    
  2. 在mvc配置文件applicationContext-mvc.xml中配置拦截器

    <mvc:interceptors>
        <mvc:interceptor>
            <!--拦截所有以settings和workbench开头的请求-->
            <mvc:mapping path="/settings/**"/>
            <mvc:mapping path="/workbench/**"/>
            <!--排除登录本身请求的拦截(优先级高)-->
            <mvc:exclude-mapping path="/settings/qx/user/toLogin.do"/>
            <mvc:exclude-mapping path="/settings/qx/user/login.do"/>
            <!--拦截器类-->
            <bean class="com.tu.crm.settings.web.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    

​ OK

复习知识点

1)同步请求和异步请求的区别
  • 同步请求:浏览器窗口发出的请求,响应信息返回到浏览器窗口,所以会进行全局刷新。
  • 异步请求:ajax发出的请求,响应信息返回到ajax的回调函数,既可以进行全局刷新,也可以进行局部刷新。

小结

  • 如果需要进行全局刷新,推荐使用同步请求,当然也可以使用异步请求
  • 如果需要进行局部刷新,只能使用异步请求
  • 如果既可能进行全局刷新,也可能进行局部刷新,也是只能使用异步请求
2)使用jquery获取指定元素的指定属性的值
  • 选择器.attr(“属性名”);
    • 来获取那些值不是true/false的属性的值
  • 选择器.prop(“属性名”);
    • 用来获取值是true/false的属性的值.例如:checked,selected,readonly,disabled等。
3)把控制层(controller)代码中处理好的数据传递到视图层(jsp),使用作用域传递
  • pageContext:用来在同一个页面的不同标签之间传递数
  • request:在同一个请求过程中间传递数据。
  • session: 同一个浏览器窗口的不同请求之间传递数据。
  • application:所有用户共享的数据,并且长久频繁使用的数据。
4)jquery事件函数的用法
5)记住密码
  1. 访问:login.jsp

    • 如果上次记住密码,自动填上账号和密码;否则,不填。
    • 如何判断上次是否记住密码?
      • 上次登录成功,判断是否需要记住密码:如果需要记住密码,则往浏览器写cookie;否则,删除cookie。而且cookie的值必须是该用户的loginAct和loginPwd
      • 下次登录时,判断该用户有没有cookie:如果有,则自动填写账号和密码;否则,不写。而且填写的是cookie的值
  2. 浏览器显示

    1. 获取cookie:

      • 使用java代码获取cookie:

         Cookie[] cs=request.getCookies();
            for(Cookie c:cs)&#123;
                if(c.getName().equals("loginAct"))&#123;
                    String loginAct=c.getValue();
                &#125;else if(c.getName().equals("loginPwd"))&#123;
                    String loginPwd=c.getValue();
                &#125;
           &#125;
        
      • 使用EL表达式获取cookie

        • ${cookie.loginAct.value}
        • ${cookie.loginPwd.value}

6)过滤器和拦截器
  • 过滤器

    • 过滤器类:

      implements Filter{
           --init //初始化过滤器,Filter生命周期中只被调用一次
           --doFilter	//每一次请求都会调用,FilterChain 用来调用下一个过滤器Filter
           --destroy //销毁或关闭资源,Filter生命周期中只被调用一次
      }
      
    • 配置过滤器:web.xml

  • 拦截器

    • 拦截器类:

      implements HandlerInterceptor{
                    --preHandle //请求处理之前进行调用,返回值为false ,将视为当前请求结束,自身拦截器失效,其他的拦截器也不再执行
                    --postHandle //preHandle()方法返回值为true时执行;Controller中的方法调用之后,DispatcherServlet返回渲染视图之前被调用
                    --afterCompletion//preHandle()方法返回值为true时执行;整个请求结束之后,DispatcherServlet 渲染了对应的视图之后执行
       }
      

      先声明的拦截器preHandle()方法先执行,postHandle()方法后执行。(看源码)

    • 配置拦截器:springmvc.xml

    • 链式调用,一个应用中可以同时存在多个拦截器Interceptor, 一个请求也可以触发多个拦截器 ,而每个拦截器的调用会依据它的声明顺序依次执行

功能上拦截器是高配版的过滤器,但他们的底层实现不同,具体请看–》


文章作者: 涂爽
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 涂爽 !
评论
 上一篇
CRM项目SSM框架构建(四) CRM项目SSM框架构建(四)
完成业务: 添加市场活动备注 删除市场活动备注 修改市场活动备注 查看市场活动明细需求分析 用户在市场活动主页面,点击市场活动名称超级链接,跳转到明细页面,完成查看市场活动明细的功能. 在市场活动明细页面,展示: 市场活动的基
2022-06-24
下一篇 
CRM项目SSM框架构建(一) CRM项目SSM框架构建(一)
CRM项目简介​ Customer Relationship Management 客户关系管理系统,企业级应用,传统应用;给销售或者贸易型公司使用,在市场,销售,服务等各个环节中维护客户关系。 CRM项目的宗旨:增加新客户,留住老客户,把
2022-06-22
  目录