1.使用IDEA创建一个基本的Maven工程
(1)打开IDEA,点击Create New Project
(3)
(4)
(5)进去之后的界面如下
(6)由于IDEA创建maven的Java web项目时,main文件夹下没有java,resources目录等源文件夹,所以我们需要自己创建,具体过程可以查看这篇博客。这样一个基本的项目结构就创建好了。
2.在pom.xml中添加该项目所需要依赖jar包
4.0.0
war
ssmtest
com.test
ssmtest
1.0-SNAPSHOT
org.mortbay.jetty
maven-jetty-plugin
6.1.7
8888
30000
${project.build.directory}/${pom.artifactId}-${pom.version}
/
org.springframework
spring-webmvc
4.3.7.RELEASE
org.springframework
spring-jdbc
4.3.7.RELEASE
org.springframework
spring-aspects
4.3.7.RELEASE
org.mybatis
mybatis
3.4.2
org.mybatis
mybatis-spring
1.3.1
c3p0
c3p0
0.9.1
mysql
mysql-connector-java
5.1.41
jstl
jstl
1.2
javax.servlet
javax.servlet-api
3.0.1
provided
junit
junit
4.12
com.fasterxml.jackson.core
jackson-core
2.9.6
com.fasterxml.jackson.core
jackson-annotations
2.9.6
com.fasterxml.jackson.core
jackson-databind
2.9.6
3.配置web.xml文件
contextConfigLocation
classpath*:spring/spring-*.xml
org.springframework.web.context.ContextLoaderListener
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/springmvc-context.xml
1
springmvc
/
encoding
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
encoding
springmvc
4.在resource目录下分别创建spring和mybatis目录,并且添加相应的配置文件
(1)spring-context.xml
classpath*:mybatis/mapper-*.xml
(2)springmvc-context.xml
(3)config.xml
(4)mapper-user.xml
包名 | 作用 |
---|---|
bean | 存放一些实体类,有些一与数据库的表相对应,例如,用户类等等 |
controller | 控制层 |
dao | 数据传输层,与数据库进行交数据交互 |
service | 编写 业务逻辑的接口 |
serviceImpl | 实现业务逻辑 |
当然了,每个人给包的命名或者结构安排可能不一样,我所给出的只是一种参考。
1.由于本文的案例比较简单,只有用户的登录和注册功能,所以在名为ssmtest的数据库(自己在MySQL创建)中只建立了一张t_user表,如下图所示。
2.在IDEA中连接到该名为ssmtest的数据库
这样便连接成功了!与此同时在User.java中添加相应的属性
User.java
package com.test.bean;
public class User {
private String username;
private String password;
//用于判断是否记住用户名
private String flag;
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="com.test.utils.*" %>
登录页面
<%
//完成用户名的回显
String username="";
//获得从客户端携带过来的所有Cookie
Cookie[] cookies=request.getCookies();
//从Cookie的数组中查找指定名称的Cookie
Cookie cookie = CookieUtils.findCookie(cookies, "username");
if(cookie!=null)
{
username=cookie.getValue();
}
%>
2.register.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
用户注册
后台的目录结构如下所示
package com.test.bean;
public class AjaxResult {
//用于后台的逻辑判断
private boolean success;
//后台向前端返回的对象
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
1.登录与注册功能
(1)控制器类 DispatcherController.java,用于转发各种请求
package com.test.controller;
import com.test.bean.AjaxResult;
import com.test.bean.User;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class DispatcherController {
@Autowired
private UserService userService;
//1.跳转到登录页面
@RequestMapping("login")
public String login(){
return "login";
}
//2.跳转到注册页面
@RequestMapping("register")
public String register(){
return "register";
}
//2.登录成功后跳转到index.jsp页面
@RequestMapping("index")
public String index(){
return "index";
}
//3.用Ajax完成登录操作,但不跳转页面
@ResponseBody
@RequestMapping("doAjaxLogin")
public Object doAjaxLogin(User user, HttpSession session, HttpServletResponse response){
//创建一个AjaxResult对象,用于保存各种
AjaxResult ajaxResult = new AjaxResult();
User dbUser = userService.queryForLogin(user);
//登录成功
if(dbUser != null){
//将用户放入session中
session.setAttribute("loginUser",dbUser.getUsername());
//获取是否记住用户名单选框的状态
if("true".equals(user.getFlag())){
// 完成记住用户名的功能:
Cookie cookie = new Cookie("username",user.getUsername());
//设置有效路径:
cookie.setPath("/ssmtest");
// 设置有效时间:
cookie.setMaxAge(60*60*24);// 保存24小时
// 将cookie回写到浏览器:
response.addCookie(cookie);
}
ajaxResult.setSuccess(true);
}else{
ajaxResult.setSuccess(false);
}
return ajaxResult;
}
//3.用Ajax完成注册操作,但不跳转页面
@ResponseBody
@RequestMapping("doAjaxRegister")
public Object doAjaxRegister(User user){
//创建一个AjaxResult对象,用于保存各种
AjaxResult ajaxResult = new AjaxResult();
User dbUser = userService.queryForLogin(user);
if(dbUser != null){
//该用户已经被注册
ajaxResult.setSuccess(false);
}else{
try {
userService.insertUser(user);
ajaxResult.setSuccess(true);
}catch (Exception e){
e.printStackTrace();
ajaxResult.setSuccess(false);
}
}
return ajaxResult;
}
}
(2).业务逻辑层(接口) UserService
package com.test.service;
import com.test.bean.User;
public interface UserService {
//查询登录用户
User queryForLogin(User user);
//注册用户
void insertUser(User user);
}
(3).业务逻辑实现 UserServiceImpl
package com.test.serviceImpl;
import com.test.bean.User;
import com.test.dao.UserDao;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User queryForLogin(User user) {
return userDao.queryForLogin(user);
}
@Override
public void insertUser(User user) {
userDao.insertUser(user);
}
}
(4)数据访问层
package com.test.dao;
import com.test.bean.User;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
@Repository
public interface UserDao {
//由于该查询语句较为简单,所以可以直接在@Select注解中写SQL语句
@Select("select * from t_user where username = #{username} and password = #{password}")
User queryForLogin(User user);
//sql语句在mapper-user.xml文件中编写
void insertUser(User user);
}
此时应该在mapper-user.xml文件中添加insertUser方法对应的SQL语句
mapper-user.xml
insert INTO t_user (username, password)
values (#{username},#{password})
2.使用拦截器阻止未登陆的用户访问index.jsp页面
可能有人会想到如果直接在浏览器中输入http://localhost:8080/ssmtest/index,那么能不能直接访问到index.jsp页面?如果在用户访问该页面之前不进行登陆信息验证的话,那么是可以直接访问到的,这显然是不安全的。所以这里可以使用SpringMVC的组件拦截器(具体相关内容可以参考我之前整理的浅谈SpringMVC中的拦截器控件)
(1)添加拦截器类LoginInteceptor.java
package com.test.web;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInteceptor implements HandlerInterceptor{
/*在拦截器拦截之前判断是否之后的操作
* @return false:不再继续执行后面的操作
* true:继续执行后面的操作
* */
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//判断当前的用户是否已经登录
HttpSession session = httpServletRequest.getSession();
String loginUser = (String)session.getAttribute("loginUser");
//用户未登陆,跳转到登录页面
if(loginUser == null){
String path = session.getServletContext().getContextPath();
httpServletResponse.sendRedirect(path + "/login");
return false;
}else{
return true;
}
}
//在拦截器拦截完毕之后进行的操作
@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 {
}
}
(2)在springmvc-context.xml文件中配置该拦截器
3.使用Cookie完成记住用户名的功能
在CookieUtils .java中创建findCookie方法,便于寻找用户名
package com.test.utils;
import javax.servlet.http.Cookie;
//在浏览器中回显用户名
public class CookieUtils {
public static Cookie findCookie(Cookie[] cookies , String name){
if(cookies == null){
// 说明客户端没有携带Cookie:
return null;
}else{
// 说明客户端携带Cookie:
for (Cookie cookie : cookies) {
if(name.equals(cookie.getName())){
return cookie;
}
}
return null;
}
}
}
其余相关的操作在前面的代码已经给出
4.防止用户多处登录
(1).创建一个用户缓存类LoginCache.java,用于在session中保存用户的相关信息,以便于之后的验证
package com.test.utils;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
public class LoginCache {
//使用单例模式
private LoginCache(){}
private static LoginCache instance = new LoginCache();
public static LoginCache getInstance(){
return instance;
}
// key值:登录用户登录名,value值:登录用户sessionId
private Map loginUserSession = new HashMap();
//key值:登录用户sessionId,value值:登录用户session对象
private Map loginSession = new HashMap();
/**
* 通过登录名获取对应登录用户的sessionId
* @param username
* @return
*/
public String getSessionIdByUsername(String username){
return loginUserSession.get(username);
}
/**
* 通过sessionId获取对应的session对象
* @param sessionId
* @return
*/
public HttpSession getSessionBySessionId(String sessionId){
return loginSession.get(sessionId);
}
/**
* 存储登录名与对应的登录sessionID至缓存对象
* @param username
* @param sessionId
*/
public void setSessionIdByUserName(String username,String sessionId){
loginUserSession.put(username, sessionId);
}
/**
* 存储sessionId与对应的session对象至缓存对象
* @param sessionId
* @param session
*/
public void setSessionBySessionId(String sessionId,HttpSession session){
loginSession.put(sessionId, session);
}
}
(2)创建LoginSessionListener类,用户监听用户属性在session中的变化
package com.test.listener;
import com.test.utils.LoginCache;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class LoginSessionListener implements HttpSessionAttributeListener{
private static final String LOGINUSER="loginUser";
@Override
public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
//获得session中添加的属性值的名称
String attrName = httpSessionBindingEvent.getName();
if(LOGINUSER.equals(attrName)){
//获取添加的属性值,即用户登录名
String attrValue = (String)httpSessionBindingEvent.getValue();
//该次操作的session对象
HttpSession session1 = httpSessionBindingEvent.getSession();
//该次操作的session对象ID
String sessionId = session1.getId();
//从缓存对象里面,获得该用户登录名对应的sessionID值
String sessionId2 = LoginCache.getInstance().getSessionIdByUsername(attrValue);
//未获得结果,不需要清理前次登录用户会话信息
if(null == sessionId2){
}else{
HttpSession session2 = LoginCache.getInstance().getSessionBySessionId(sessionId2);//获取前次该用户登录对应的session对象
//清理前次登录用户会话存储信息,使得前次登录失效
session2.invalidate();
}
//完成该次登录用户登录名、sessionID,session对象的缓存对象存储
LoginCache.getInstance().setSessionIdByUserName(attrValue, sessionId);
LoginCache.getInstance().setSessionBySessionId(sessionId, session1);
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
}
@Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
}
}
(3)在web.xml文件中注册该监听器
contextConfigLocation
classpath*:spring/spring-*.xml
org.springframework.web.context.ContextLoaderListener
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring/springmvc-context.xml
1
springmvc
/
encoding
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
encoding
springmvc
com.test.listener.LoginSessionListener
这样一来,若同一个用户在两处登录同一个账号时,那么前一个登录的用户信息会被清除,并且由拦截器拦截到用户信息在session中为空之后,直接跳转到login.jsp页面,这样便实现了同一个用户不能多处登录。
好啦!到这里为止,一个基于SSM框架的登录注册案例便完成了。一些必要的注释我已经在代码中给出,由于文字不能完全地还原整个开发过程,所以给出的代码顺序会存在一些前后台不同步的情况,不过给出的代码应该是完整的。如果大家发现了错误可以直接提出来哦~~
该案例源码:ssmtest
提取码:86rm