转自http://coder520.com/
一、完成登录前端
1、在login模块创建controller方法去处理请求
2、创建static文件,修改login.vm文件
3、springmvc静态资源加载的问题
前端去请求这些静态资源,只需要服务器给它就像,而不需要springmvc去处理这些请求,但是springmvc是不知道这些静态资源不需要处理它会把这些请求处理去找controller所以会出现404.需要在springmvc.xml里配置默认处理器,专门处理静态资源
<!--处理静态资源-->
<mvc:default-servlet-handler/>
4、在账号和密码下创建span隐藏域用于警告,并且修改用于提交的js代码(前端校验)
<div class="form-group has-feedback">
<input id="user" type="text" class="form-control" placeholder="用户名">
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
<span id="user_alert" style="color: red; visibility: hidden">请输入账号</span>
</div>
<script>
$(function () {
$("#submitId").click(function () {
var user = $("#user").val();
var pwd = $("#pwd").val();
var veryfiy = true;
if (user.length == 0) {
$("#user_alert").css("visibility", "visible");
veryfiy = false;
} else {
$("#user_alert").css("visibility", "hidden");
}
if (pwd.length == 0) {
$("#pwd_alert").css("visibility", "visible");
veryfiy = false;
} else {
$("#pwd_alert").css("visibility", "hidden");
}
if(veryfiy){
$("#form_submit").submit();
}
})
});
</script>
二、登录后台
1、用md5存密码,不能从消息摘要反推密码。创建安全工具类。里面两个方法加密方法和校验密码方法。
加密方法,加密后会乱码需要base64来解码
public String encrptyPassword(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md5 = MessageDigest.getInstance("MD5");
BASE64Encoder base64Encoder = new BASE64Encoder();
String result = base64Encoder.encode(md5.digest(password.getBytes("utf-8")));
return result;
}
校验方法,两个参数一个是传入的,一个是数据库里的,先对传入的md5加密之后与数据库里的对比。
public boolean checkPassword(String inputPwd, String dbPwd) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String result = encrptyPassword(inputPwd);
if (result.equals(dbPwd)) {
return true;
}
return false;
}
接着写login模块的contrller,添加后端校验检查的方法
@RequestMapping("/check")
public String checkLogin(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
//查数据库,如果查到数据 调用MD5加密对比密码
//校验成功
//用户信息保存session
//校验失败
}
这里有一个问题,当校验成功就跳转到首页,当校验失败就跳转登录页,跳转得刷新页面,这样不方便,所以前端使用ajax来提交数据,这样当失败或者成功的时候不用刷新页面也就来到登录页或首页。ajax最后一个data不是传过去的data而是请求成功后后端返回的data。
if(veryfiy){
//ajax提交表单
$.ajax({
type:"POST",
url:"/login/check",
data:{"username":user, "password":pwd},
success:function (data) {
alert(data);
}
})
}
controller层需要修改一下,首先登录页面的url,我们想要输入http://localhost:8080/login就来到登录页面,不能只有类mapping,还是得有一个空mapping的方法返回字符串mvc才能找到在web-inf下的.vm显示。所以这里有个login方法,上面ajax的请求url为check第二个方法,这个方法我们返回一个json,然后在前端显示一下,所以要加上@ResponseBody,如果没有加上,我们又没有login_succ.vm它是找不到的。
@Controller
@RequestMapping("login")
public class LoginController {
@RequestMapping
public String login() {
return "login";
}
@RequestMapping("/check")
@ResponseBody
public String checkLogin(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
//查数据库,如果查到数据 调用MD5加密对比密码
//校验成功
//用户信息保存session,返回成功signal
//校验失败,返回失败signal
return "login_succ";
}
}
开始查询
login模块的controller
//查数据库,如果查到数据 调用MD5加密对比密码
User user = userService.findUserByName();
user的service
@Override
public User findUserByName() {
User user = userMapper.selectByName();
return user;
}
user的mapper.xml,这里不用设置参数因为它没有找到参数就自动调用,不用设置也可以。
<select id="selectByName" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from user
where username = #{username}
</select>
让数据库里注册用户以便供登录测试
controller添加,这里用postman来请求该方法,传过来的json数据,所以需要加上@RequestBody注解
@RequestMapping("/register")
@ResponseBody
public String register(@RequestBody User user){
userService.createUser(user);
return "succ";
}
service,这里需要注意在service执行数据库操作要抛出异常有两种方式,一种是往上抛抛到调用它的controller,另一种是trycatch捕获异常,而trycatch要注意我们插入数据需要事务的支持可能有多个数据库操作,也就是说有可能会回滚,而回滚是需要捕获异常才会回滚,而trycatch已经把异常捕获了,它就不能回滚了,所以我们需要在trycatch里把异常在抛出去。它才会回滚,抛给上面的好处,不用重新抛,trycatch的好处可以记录日志,但是需要重新抛出异常还有这里要把SecurityUtils里的方法设置为static
@Override
public void createUser(User user) throws UnsupportedEncodingException, NoSuchAlgorithmException {
user.setPassword(SecurityUtils.encrptyPassword(user.getPassword()));
userMapper.insertSelective(user);
}
这里往上抛,controller还得继续往上抛
public String register(@RequestBody User user) throws UnsupportedEncodingException, NoSuchAlgorithmException {
最后抛到页面就显示500错误,我们可以使用springmvc来错误处理,它有这个功能。
postman请求
发送之后这里报415错误,原因是我们springmvc只配置了对页面的解析没有配置对json的解析,所以报json格式不支持。在springmvc下配置信息转换器
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=utf-8</value>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
但是添加之后还是415,然后百度了一下,第一步就知道了https://blog.csdn.net/yixiaoping/article/details/45281721#comments原来我开启了两个注解。。。上面还有一个去掉就行了。。。原理就是扫描到@RequestBody然后就把用fastjson把json转换为java对象。
数据库里有数据之后就可以登录试试看了,后端校验代码,当和密码和数据库校验成功就存入session,这样当访问home主页的时候可以判断是否有session,如果没有就跳转到登录有就直接登录。
@RequestMapping("/check")
@ResponseBody
public String checkLogin(HttpServletRequest request) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String username = request.getParameter("username");
String password = request.getParameter("password");
//查数据库,如果查到数据 调用MD5加密对比密码
User user = userService.findUserByName(username);
if (user != null) {
if (SecurityUtils.checkPassword(password, user.getPassword())){
// 检验成功 设置session
request.getSession().setAttribute("userinfo", user);
return "login_succ";
}else {
//校验失败,返回校验失败signal
return "login_fail";
}
} else {
//校验失败,返回校验失败signal
return "login_fail";
}
}
接下来如果有人想访问首页就需要判断session是否有值。所以需要写个拦截器,首先实现HandleInterceptor,我们只需要重写请求到达之前的方法,获取url判断是否包含login,如果有就不拦截,如果没有就拦截然后判断session里是否有userinfo,如果没有就转发到登录。
public class SessionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
//拦截请求到达之前
String uri = request.getRequestURI();
//如果url里包含了login就不拦截,包括loginxxx
if (uri.indexOf("login") >= 0) {
return true;
}
//检查session是否有userinfo
HttpSession session = request.getSession();
User user = (User) session.getAttribute("userinfo");
if (user != null) {
return true;
}
//转发到登录
request.getRequestDispatcher("/login").forward(request, response);
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
接着在springmvc里配置过滤器,但是这里如果只配置bean而没有拦截器的url是表示拦截所有请求,连static下的资源都拦截,这样不行,等下请求后资源全没显示。我们需要过滤掉这些样式资源,
<!--配置过滤器-->
<mvc:interceptors>
<bean class="com.ljs.common.Interceptor.SessionInterceptor"/>
</mvc:interceptors>
之前spring-mvc里有个处理静态资源的servlet,我们需要在web.xml里配置该servelt的mapper这样就不会连资源也拦截了。如下
<!--处理静态资源-->
<mvc:default-servlet-handler/>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
接着创建首页和方法和vm页面,注意这个方法是放在user模块的controller而不是login因为我们拦截非login,如果是在login下不就不拦截,那拦截器就没意义了
@RequestMapping("/home")
public String home(){
return "home";
}
ok这样就能拦截那些没登录然后对主页发起的请求,接着写账号或者密码错误的提示和登录成功的window跳转
<span id="login_error" style="color: red; visibility: hidden">账户密码错误,请重新输入!</span>
当后端校验成功返回login_succ之后我们就使用window跳转到主页,但是这里跳转不了,调试前端发现data返回的是““login_succ””,原因是fastjson把返回的字符串数据给转成json对象了。我们需要在spring-mvc里加上spring对字符串转换的bean
if (veryfiy) {
//ajax提交表单
$.ajax({
type: "POST",
url: "/login/check",
data: {"username": user, "password": pwd},
success: function (data) {
if (data == "login_succ") {
window.location.href("/user/home");
}else {
$("#login_error").css("visibility", "visible");
}
}
})
}
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
这样就ok了。
配置404和505页面还有首页home页面,自己去找springmvc配置错误,可以精确到sql错误啊啥的。
在web.xml里加上
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>