基于SSM的物业管理系统(登录、注册、找回密码、MD5、JavaMail、防止html注入篇)

大兔子大兔子 提交于 2019-11-27 16:11:52

搭建SSM

      对新手来说搭建SSM框架是痛苦的(我就是),通过朋友和这篇博客:SSM第一篇 最简单的SSM框架搭建过程–SSM简单整合的帮助最后还是搭建好了。

提几个搭建时候遇到的问题:
      1. 逆向生成工具是自动生成Dao、Mapping、Pojo的工具,路径放在跟src同目录下可以避免生成路径的烦恼。
      2. 生成的Dao文件名为xxMapper,如有需要可以改为xxDao,我这里嫌麻烦就没有改。
      3. 注意不要拦截静态文件(css等),不然前端样式无法显示,我是在web.xml中配置的。
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>

      4. 在编写SendMail类的时候,要将类注释为控件(@Component),在声明该类的时候要用@Autowired标注在类上,完成自动装配的工作。

    @Autowired
    SendMail sendMail;

接下来进入正题

登录

      登录界面具有记住密码找回密码登录注册功能。登录:首先判断账号密码是否为空,之后判断数据库是否存在该账号,最后判断密码是否正确,由于密码采用MD5加密,所以通过对输入的密码进行MD5之后再与数据库的密码进行比较,正确则进入系统;找回密码:采用给邮箱发验证码的形式进行重置(MD5无法反编码);记住密码:用cookie保存用户账号、密码;注册:采用Java mail工具类,用自己的QQ邮箱给用户邮箱发送验证码。
FrontLoginController.java:

    /**
     * 跳转到前台登录页面
     * @return login.jsp
     */
    @RequestMapping("/login")
    public String login(){
        return "/front/login";
    }

login.jsp:

  <form id="frontLoginForm" action="${pageContext.request.contextPath}/frontLogin/check" method="post"> 
   <fieldset> 
    <div> 
     <c:choose> 
      <c:when test="${not empty loginEmail}"> 
       <input value="${requestScope.loginEmail}" id="email" name="email" type="email" autofocus="" /> 
      </c:when> 
      <c:otherwise> 
       <input placeholder="E-mail" id="email" name="email" type="email" autofocus="" /> 
      </c:otherwise> 
     </c:choose> 
    </div> 
    <div > 
     <input placeholder="密码" id="password" name="password" type="password" value="" /> 
    </div> 
    <div > 
     <label> <input id="remember" name="remember" type="checkbox" value="Remember Me" />记住密码 </label> 
    </div> 
    <div >
    <a href="${pageContext.request.contextPath}/frontLogin/forget" style="float:right"> 忘记密码 </a>
    <a href="${pageContext.request.contextPath}/frontRegister/register"> 注册 </a>
    </div> 
    <font size="4" color="red"> ${loginError} </font> 
    <button type="submit" class="btn btn-lg btn-success btn-block">登录</button>
   </fieldset> 
  </form>

记住密码

<script>
        window.onload = function(){
            var oForm = document.getElementById('frontLoginForm');
            var oUser = document.getElementById('email');
            var oPswd = document.getElementById('password');
            var oRemember = document.getElementById('remember');
            //页面初始化时,如果帐号密码cookie存在则填充
            if(getCookie('email') && getCookie('password')){
              oUser.value = getCookie('email');
              oPswd.value = getCookie('password');
              oRemember.checked = true;
            }
            //复选框勾选状态发生改变时,如果未勾选则清除cookie
            oRemember.onchange = function(){
              if(!this.checked){
                delCookie('email');
                delCookie('password');
              }
            };
            //表单提交事件触发时,如果复选框是勾选状态则保存cookie
            oForm.onsubmit = function(){
              if(remember.checked){ 
                setCookie('email',oUser.value,7); //保存帐号到cookie,有效期7天
                setCookie('password',oPswd.value,7); //保存密码到cookie,有效期7天
              }
            };
        };
        //设置cookie
        function setCookie(name,value,day){
            var date = new Date();
            date.setDate(date.getDate() + day);
            document.cookie = name + '=' + value + ';expires='+ date;
        };
        //获取cookie
        function getCookie(name){
            var reg = RegExp(name+'=([^;]+)');
            var arr = document.cookie.match(reg);
            if(arr){
              return arr[1];
            }else{
              return '';
            }
        };
        //删除cookie
        function delCookie(name){
            setCookie(name,null,-1);
        };
    </script>

FrontLoginController.java
      用session来保存用户的账号密码,session的信息存在服务器,sessionId保存在客户端的cookie中,因为使用同一个session保存用户信息,所以限制了一个浏览器只能登录一个用户。登录系统前判断是否已经存在该session,存在则判断是否是登录的那个账号,是的话重新进入系统,不是则返回登录界面。

    /**
     * 检测业主信息是否存在,登录系统
     * @param request
     * @param session
     * @return login.jsp 或 index.jsp
     */
    @RequestMapping(value = "/check", method = RequestMethod.POST)
    public ModelAndView check(HttpServletRequest request, HttpSession session){
        String email = request.getParameter("email");
        String password = request.getParameter("password");

        ModelAndView mv = new ModelAndView();
        mv.addObject("loginEmail", email);
        mv.setViewName("/front/login");

        if(email.equals("")){
            request.setAttribute("loginError", "邮箱不能为空");
            return mv;
        }else{
            if(password.equals("")){
                request.setAttribute("loginError", "密码不能为空");
                return mv;
            }
        }
        //从数据库获取对应的用户
        Owner owner = frontLoginService.getByEmail(email);
        if(owner == null){
            request.setAttribute("loginError", "业主不存在");
            return mv;
        }

        //获取输入密码的MD5形式
        MD5 md5 = new MD5();
        String md5Password = md5.getMD5(password);
        if(md5Password.equals(owner.getOwnersPassword())){

            mv.setViewName("/front/index");

            Owner sessionOwner = (Owner) session.getAttribute("owner");
            //已经存在session
            if(sessionOwner != null ){
                String sessionEmail = sessionOwner.getOwnersEmail();
                //重复登录
                if(sessionEmail.equals(email)){
                    return mv;
                }else{
                    mv.setViewName("/front/login");
                    request.setAttribute("loginError", "同一浏览器不能登录多个账号,请使用其他浏览器");
                    return mv;
                }
            //不存在session
            }else{
                session.setAttribute("owner", owner);
                return mv;
            }
        }else{
            request.setAttribute("loginError", "密码不正确");
            return mv;
        }
    }

注册

      注册业主需要保证业主的邮箱是有效邮箱,不然无法通过验证码校检;验证码由6个0-9的正整数随机而成,每个发送成功的验证码都存到emailcode表中;注册时要填写相应的单元号,每个单元房只能有一个账号注册。

FrontRegisterController

    /**
     * 跳转到注册页面
     * @return register.jsp
     */
    @RequestMapping("/register")
    public String register(){
        return "/front/register";
    }

register.jsp

<form action="${pageContext.request.contextPath}/frontRegister/check" method="post"> 
   <fieldset> 
    <div> 
     <c:choose> 
      <c:when test="${not empty registerEmail}"> 
       <input value="${requestScope.registerEmail}" id="email" name="email" type="email" required="" autofocus="" /> 
      <a href="javascript:void" style="float:center" onclick="getEmail()">发送验证码</a>
      </c:when> 
      <c:otherwise> 
       <input placeholder="E-mail" id="email" name="email" type="email" required="" autofocus="" /> 
       <a href="javascript:void" style="float:center" onclick="getEmail()">发送验证码</a>
      </c:otherwise> 
     </c:choose> 
    </div> 
    <div > 
     <input placeholder="验证码" name="code" type="text" required="" /> 
    </div> 
    <div> 
     <c:choose> 
      <c:when test="${not empty registerPassword}"> 
       <input value="${requestScope.registerPassword}" id="pwd1" name="password" type="password" required="" onkeyup="checkLength()" /> 
       <span id="spanLen"></span> 
      </c:when> 
      <c:otherwise> 
       <input placeholder="密码" id="pwd1" name="password" type="password" required="" onkeyup="checkLength()" /> 
       <span id="spanLen"></span> 
      </c:otherwise> 
     </c:choose> 
    </div> 
    <div> 
     <input placeholder="确认密码" id="pwd2" name="password2" type="password" required="" onblur="checkPSW()" /> 
     <span id="pswInfo" style="color: #c41a15;"></span> 
    </div> 
    <div> 
     <c:choose> 
      <c:when test="${not empty registerRoomId}"> 
       <input value="${requestScope.registerRoomId}" name="roomId" type="text" required="" /> 
      </c:when> 
      <c:otherwise> 
       <input placeholder="单元号" name="roomId" type="text" required="" /> 
      </c:otherwise> 
     </c:choose> 
    </div> 
    <font size="3"> <a href="${pageContext.request.contextPath}/frontLogin/login" style="float:center">已有账号,登录</a> </font> 
    <font size="4" color="red"> ${loginError} </font> 
    <button id="btregister" type="submit" >注册</button> 
   </fieldset> 
  </form>

判断密码强度、发送验证码(script)

    <script>  
        function checkLength(){  
            var pwd1 = document.getElementById("pwd1").value;  
            var spanLen = document.getElementById("spanLen");  
            if(pwd1.length <= 3 && pwd1.length > 0)  
                spanLen.innerHTML="密码强度:弱";  
            else if(pwd1.length <= 6)  
                spanLen.innerText="密码强度:中";  
            else  
                spanLen.innerText="密码强度:强";  
        }  
        function checkPSW(){
            var pwd1 = document.getElementById("pwd1").value;  
            var pwd2 = document.getElementById("pwd2").value;  
            var pswInfo = document.getElementById("pswInfo");  
            if(pwd1 != pwd2){
                pswInfo.innerText="两次密码不同";
                document.getElementById("btregister").disabled = true;
            }
            else {
                pswInfo.innerText="";
                document.getElementById("btregister").disabled = false;
            } 
        }
        function getEmail(){
            var email = document.getElementById("email").value; 
            if(email != ''){
                window.location.href = "${pageContext.request.contextPath}/frontRegister/registerCode?email="+email;
            }else{
                alert("邮箱不能为空");
            }
        }
    </script> 

FrontLoginController.java

    /**
     * 发送注册验证码
     * @param request
     * @return register.jsp
     */
    @RequestMapping("/registerCode")
    public ModelAndView forget(HttpServletRequest request){

        String email = request.getParameter("email");

        ModelAndView mView = new ModelAndView();
        mView.addObject("registerEmail", email);
        mView.setViewName("/front/register");

        Owner owner = ownerService.selectByEmail(email);
        if(owner != null){
            request.setAttribute("loginError", "该邮箱已经注册");
            return mView;
        }
        //随机生成六位0-9的正整数作为验证码
        StringBuffer code = new StringBuffer();
        Random random = new Random();
        for (int i=0; i<6; i++) {
            code.append(random.nextInt(10));
        }
        //发送邮件
        try {
            sendMail.sendCode(email, code.toString());
        } catch (Exception e) {
            request.setAttribute("loginError", "邮箱不存在");
            return mView;
        }
        //用emailcode表保存验证码
        EmailCode existCode = emailCodeService.getByEmail(email);
        //插入验证码
        if(existCode == null){
            EmailCode emailCode = new EmailCode();
            emailCode.setOwnersEmail(email);
            emailCode.setCodeNum(code.toString());
            emailCodeService.insertByNoId(emailCode);
        //更新验证码
        }else{
            emailCodeService.updateByEmail(code.toString(), email);
        }
        return mView;
    }

检查注册的用户信息是否符合规范

    /**
     * 判断是否符合规定,注册新用户
     * @param request
     * @param session
     * @return true:index.jsp false:register.jsp
     */
    @RequestMapping(value = "/check", method = RequestMethod.POST)
    public ModelAndView setOwner (HttpServletRequest request, HttpSession session){
        String registerEmail = request.getParameter("email");
        String registerPassword = request.getParameter("password");
        int registerRoomId = Integer.valueOf(request.getParameter("roomId"));
        String inputCode = request.getParameter("code");

        Owner existOwner = frontRegisterService.getByEmail(registerEmail);

        ModelAndView mView = new ModelAndView();
        mView.addObject("registerEmail", registerEmail);
        mView.addObject("registerPassword", registerPassword);
        mView.addObject("registerRoomId", registerRoomId);
        mView.setViewName("/front/register");

        if(existOwner != null){
            request.setAttribute("loginError", "该邮箱已注册");
            return mView;
        }

        //判读验证码是否相同
        EmailCode emailCode = emailCodeService.getByEmail(registerEmail);
        String existCode = emailCode.getCodeNum();
        if(!inputCode.equals(existCode)){
            request.setAttribute("loginError", "验证码不正确");
            return mView;
        }
        //判断是否存在单元房是否存在
        Room existRoom = roomService.getByPrimaryKey(registerRoomId);
        if(existRoom != null ){
            if(existRoom.getRoomOwner() == null){
                //对密码进行加密
                MD5 md5 = new MD5();
                String registerPasswordMD5 = md5.getMD5(registerPassword);

                Owner owner = new Owner();
                owner.setOwnersEmail(registerEmail);
                owner.setOwnersPassword(registerPasswordMD5);
                owner.setRoomId(registerRoomId);

                //增加新业主
                ownerService.insertByRegister(owner);

                //修改room房主id
                Owner roomOwner = ownerService.selectByEmail(registerEmail);
                if(roomOwner != null){
                    int ownerId = roomOwner.getOwnersId();
                    roomService.updateByRegister(ownerId, registerRoomId);
                }

                session.setAttribute("owner", owner);

                mView.setViewName("/front/index");
                return mView;
            }else{
                request.setAttribute("loginError", "该房间已被注册,如有疑问请联系管理员");
                return mView;
            }
        }else{
            request.setAttribute("loginError", "房间不存在");
            return mView;
        }
    }

找回密码

      通过输入邮箱并给邮箱发送验证码,将验证码存到数据库,再校检输入的验证码和存在数据库的是否相同,MD5无法反编码所以只能对密码进行重置。

    /**
     * 跳转到忘记密码页面
     * @return forget.jsp
     */
    @RequestMapping(value = "/forget")
    public String forget(){
        return "/front/forget";
    }

forget.jsp,判断密码强度、判断两次密码是否相同、发送验证码的js不再重贴

<form action="${pageContext.request.contextPath}/frontLogin/updatePWD" method="post"> 
   <fieldset> 
    <div> 
     <c:choose> 
      <c:when test="${not empty forgetEmail}"> 
       <input id="email" value="${requestScope.forgetEmail}" name="email" type="email" required="" autofocus="" /> 
       <a href="javascript:void" style="float:center" onclick="getEmail()">发送验证码</a> 
      </c:when> 
      <c:otherwise> 
       <input id="email" placeholder="E-mail" name="email" type="email" required="" autofocus="" /> 
       <a href="javascript:void" style="float:center" onclick="getEmail()">发送验证码</a>
      </c:otherwise> 
     </c:choose> 
    </div> 
    <div > 
     <input placeholder="验证码" name="code" type="text" required="" /> 
    </div> 
    <div > 
     <c:choose> 
      <c:when test="${not empty updatePassword}"> 
       <input value="${requestScope.updatePassword}" id="pwd1" name="password" type="password" required="" onkeyup="checkLength()" /> 
       <span id="spanLen"></span> 
      </c:when> 
      <c:otherwise> 
       <input placeholder="密码" id="pwd1" name="password" type="password" required="" onkeyup="checkLength()" /> 
       <span id="spanLen"></span> 
      </c:otherwise> 
     </c:choose> 
    </div> 
    <div > 
     <input placeholder="确认密码" id="pwd2" name="password2" type="password" required="" onblur="checkPSW()" /> 
     <span id="pswInfo" style="color: #c41a15;"></span> 
    </div> 
    <a href="${pageContext.request.contextPath}/frontLogin/login" style="float:center">已有账号,登录</a>
    <font size="4" color="red"> ${loginError} </font> 
    <button id="btforget" type="submit" >更新密码</button> 
   </fieldset> 
  </form>

发送验证码的Controller也不再重贴了。
重置密码(更新密码):

    /**
     * 判断验证码是否正确、更新密码操作
     * @param request
     * @return true:login.jsp false:forget.jsp
     */
    @RequestMapping(value = "/updatePWD", method = RequestMethod.POST)
    public ModelAndView updatePWD(HttpServletRequest request){
        String email = request.getParameter("email");
        String inputCode = request.getParameter("code");
        String password = request.getParameter("password");

        ModelAndView mv = new ModelAndView();
        mv.addObject("forgetEmail", email);
        mv.addObject("updatePassword", password);
        mv.setViewName("/front/forget");

        EmailCode emailCode = emailCodeService.getByEmail(email);
        String existCode = emailCode.getCodeNum();

        if(!inputCode.equals(existCode)){
            request.setAttribute("loginError", "验证码不正确");
            return mv;
        }

        Owner owner = frontLoginService.getByEmail(email);
        if(owner == null){
            request.setAttribute("loginError", "业主不存在");
            return mv;
        }

        MD5 md5 = new MD5();
        String md5Password = md5.getMD5(password);

        ownerService.updatePasswordByEmail(md5Password, email);

        mv.setViewName("/front/login");
        return mv;
    }

防止html注入

      由于网站存在input这样的输入框,所以不免的有人会将html的语法插入到网站中,为了防止这种情况发生,需要做的是将输入内容中的特殊符号例如:< 等替换成对应的实体名称。以上代码中E-Mail有固定的格式、密码需要MD5加密并且不需要显示,所以没有用到这个功能,但是后序的功能中(如:发布公告等)将会使用,问我为什么没有防止SQL注入?因为MyBatis自带呀。

public class CleanStyle {
    public String cleanStyle(String str){

        // " < "  ->  &lt;
        String s1 = str.replace("&", "&amp");

        // " > "  ->  &gt;
        String s2 = s1.replace(">", "&gt;");

        // " & "  ->  &amp;
        String s3 = s2.replace("<", "&lt;");

        // " " "  ->  &quot;
        String s4 = s3.replace("\"", "&quot;");

        // " ' "  ->  &apos;
        String s5 = s4.replace("\'", "&apos;");

        return s5;
    }
}

使用时只要实例化类并将内容作为参数调用cleanStyle方法就可以。

MD5加密

public class MD5 {
    public String getMD5(String password){
        String md5Password = null;
        try {
            // 得到一个信息摘要器
            MessageDigest digest = MessageDigest.getInstance("md5");
            byte[] result = digest.digest(password.getBytes());
            StringBuffer buffer = new StringBuffer();
            // 把每一个byte 做一个与运算 0xff;
            for (byte b : result) {
                // 与运算
                int number = b & 0xff;
                String str = Integer.toHexString(number);
                if (str.length() == 1) {
                    buffer.append("0");
                }
                buffer.append(str);
            }
            md5Password = buffer.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return md5Password;
    }
}

发送邮件

      粗率讲一下过程:首先要讲mail.jar导入到项目中,之后在配置文件加入如下代码,最后调用sendMail方法就可以。

<!-- 使用QQ邮箱发送邮件 -->
    <bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
        <property name="host" value="smtp.qq.com"/>
        <property name="port" value="465"/>
        <property name="username" value="xxx@qq.com"/>
        <!-- qq邮箱的授权码,如果是企业邮箱,则使用登录密码 -->
        <property name="password" value="xxx"/>

        <property name="javaMailProperties">
            <props >
                <prop key="mail.smtp.auth">true</prop>
                <prop key="mail.smtp.ssl.enable">true</prop>
                <prop key="mail.smtp.timeout">25000</prop>
                <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
            </props>
        </property>
    </bean>

发送验证码的类

    @Component
public class SendMail {
    @Autowired
    private JavaMailSender javaMailSender;

    /**
     * @Description: 执行发送邮件
     * @param to            收件人邮箱
     * @param subject        邮件主题
     * @param content        邮件内容
     */
    public void sendCode(String toEmail, String code) throws Exception {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom("xxx@qq.com");
        message.setTo(toEmail);
        message.setSubject("物业管理系统邮件服务");
        message.setText("您的验证码是:" + code);
        javaMailSender.send(message);
    }
}

      到此这篇博客就结束了,有许多不足的地方,如没做单点登录,密码强度检测太简单,没有优化代码等等,这里我就抛砖引玉了。吐槽一下markdown没有开头空两格的功能,对于写过许多作文的我来说真是难受,活生生用6个nbsp代替了……

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!