搭建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){
// " < " -> <
String s1 = str.replace("&", "&");
// " > " -> >
String s2 = s1.replace(">", ">");
// " & " -> &
String s3 = s2.replace("<", "<");
// " " " -> "
String s4 = s3.replace("\"", """);
// " ' " -> '
String s5 = s4.replace("\'", "'");
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代替了……
来源:CSDN
作者:Dkangel
链接:https://blog.csdn.net/Dkangel/article/details/80001961