数据库准备
-- MySQL dump 10.13 Distrib 8.0.27, for Win64 (x86_64)
--
-- Host: 127.0.0.1 Database: spring
-- ------------------------------------------------------
-- Server version 8.0.27
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `login_log`
--
DROP TABLE IF EXISTS `login_log`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `login_log` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int DEFAULT NULL COMMENT '用户id',
`ip` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登录IP',
`create_time` datetime DEFAULT NULL COMMENT '登录时间',
`update_time` datetime DEFAULT NULL,
`status` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='登录日志';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `login_log`
--
LOCK TABLES `login_log` WRITE;
/*!40000 ALTER TABLE `login_log` DISABLE KEYS */;
/*!40000 ALTER TABLE `login_log` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `user`
--
DROP TABLE IF EXISTS `user`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户名',
`password` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码',
`last_visit` datetime DEFAULT NULL COMMENT '上次登录时间',
`last_ip` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '上次登录IP',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`status` int DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `user`
--
LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'admin','1234',NULL,NULL,NULL,NULL,1);
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-11-12 16:29:37
在 IDEA 中新建 maven 项目 SpringHello,pom.xml 文件配置如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>SpringHello</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>3.2.18.RELEASE</spring.version>
<servlet.version>2.5</servlet.version>
<jstl.version>1.2</jstl.version>
<aspectjweaver.version>1.9.8.RC2</aspectjweaver.version>
<dbcp.version>1.4</dbcp.version>
<mysql.version>8.0.27</mysql.version>
<testng.version>7.4.0</testng.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectjweaver.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${dbcp.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringHello</finalName>
</build>
</project>
建立实体类对象
User 类
package com.demo.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private int id;
private String username;
private String password;
private Date lastVisit;
private String lastIp;
private Date createTime;
private Date updateTime;
private int status;
// getter/setter 省略
}
LoginLog 类
package com.demo.domain;
import java.io.Serializable;
import java.util.Date;
public class LoginLog implements Serializable {
private int id;
private int userId;
private String ip;
private Date createTime;
private Date updateTime;
private int status;
// getter/setter 省略
}
数据库访问对象
UserDao
package com.demo.dao;
import com.demo.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 根据用户名和密码查询匹配的用户数
*
* @param username 用户名
* @param password 密码
* @return 0/1
*/
public int getMatchCount(String username, String password) {
String sql = "select count(*) from user where username = ? and password = ?";
return jdbcTemplate.queryForInt(sql, username, password);
}
/**
* 根据用户名查询对应用户
*
* @param username 用户名
* @return id,username
*/
public User findUserByUsername(final String username) {
String sql = "select id, username from user where username = ? and status = 1";
final User user = new User();
jdbcTemplate.query(sql, new Object[]{username}, new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
}
});
return user;
}
/**
* 更新用户登录信息
*
* @param user lastVisit,lastIp,id
*/
public void updateLoginInfo(User user) {
String sql = "update user set last_visit = ?, last_ip = ? where id = ?";
jdbcTemplate.update(sql, user.getLastVisit(), user.getLastIp(), user.getId());
}
}
LoginLogDao
package com.demo.dao;
import com.demo.domain.LoginLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class LoginLogDao {
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* 新增用户登录记录
*
* @param loginLog userId,ip
*/
public void insertLoginLog(LoginLog loginLog) {
String sql = "insert into login_log(user_id, ip, create_time, status) values(?, ?, now(), 1)";
jdbcTemplate.update(sql, loginLog.getUserId(), loginLog.getIp());
}
}
在 resource 目录新增 Spring 配置文件 applicationContext.xml,装配 Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入-->
<context:component-scan base-package="com.demo.dao"/>
<!--定义一个使用DBCP实现的数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.cj.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/spring"
p:username="root"
p:password="1234"/>
<!--定义JDBC模板Bean-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
</beans>
业务层 UserService
package com.demo.service;
import com.demo.dao.LoginLogDao;
import com.demo.dao.UserDao;
import com.demo.domain.LoginLog;
import com.demo.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private LoginLogDao loginLogDao;
public boolean hasMatchUser(String username, String password) {
return userDao.getMatchCount(username, password) > 0;
}
public User findUserByUsername(String username) {
return userDao.findUserByUsername(username);
}
public void loginSuccess(User user) {
userDao.updateLoginInfo(user);
LoginLog loginLog = new LoginLog();
loginLog.setUserId(user.getId());
loginLog.setIp(user.getLastIp());
loginLogDao.insertLoginLog(loginLog);
}
}
继续在 applicationContext.xml 文件中装配 UserService,并配置事务管理器
<!--扫描service类包,应用Spring的注解配置-->
<context:component-scan base-package="com.demo.service"/>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!--通过AOP配置提供事务增强,让service包下的所有Bean的所有方法拥有事务-->
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceMethod" expression=" execution(* com.demo.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
增加业务层单元测试
package com.demo.service;
import com.demo.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@ContextConfiguration(locations = {"/applicationContext.xml"})
public class UserServiceTest extends AbstractTestNGSpringContextTests {
@Autowired
private UserService userService;
@Test
public void testHasMatchUser() {
assertTrue(userService.hasMatchUser("admin", "1234"));
assertFalse(userService.hasMatchUser("admin", "1111"));
}
@Test
public void testFindUserByUsername() {
User user = userService.findUserByUsername("admin");
assertEquals(user.getId(), 1);
}
@Test
public void testLoginSuccess() {
}
}
可以运行单元测试查看结果
配置 web.xml,使 Web 应用启动时自动启动 Spring 容器
<?xml version="1.0" encoding="utf-8" ?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!--从类路径下加载Spring配置文件,classpath关键字特指在类路径下加载-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--负责启动Spring容器的监听器,将引用上下文参数获得的Spring配置文件地址-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>viewspace</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>viewspace</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
LoginController 控制器类
package com.demo.web;
import com.demo.domain.User;
import com.demo.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.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@Controller
@RequestMapping(value = "/admin")
public class LoginController {
@Autowired
private UserService userService;
@RequestMapping(value = "/login.html")
public String loginPage() {
return "login";
}
@RequestMapping(value = "loginCheck.html")
public ModelAndView loginCheck(HttpServletRequest request, User user) {
boolean isValidUser = userService.hasMatchUser(user.getUsername(), user.getPassword());
if (!isValidUser) {
return new ModelAndView("login", "error", "用户名或密码错误。");
} else {
User u = userService.findUserByUsername(user.getUsername());
u.setLastIp(request.getRemoteAddr());
u.setLastVisit(new Date());
userService.loginSuccess(u);
request.getSession().setAttribute("user", u);
return new ModelAndView("main");
}
}
}
在 WEB-INF 下新增 viewspace-servlet.xml,配置 Spring MVC
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.demo.web"/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:viewClass="org.springframework.web.servlet.view.JstlView"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp"/>
</beans>
在 WEB-INF 新增文件夹 jsp,增加 login.jsp 和 main.jsp 文件
<%--
User: GeBron
Date: 2021/11/12 13:40
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>景区网站管理员登录</title>
</head>
<body>
<c:if test="${!empty error}">
<font color="red"><c:out value="${error}"/></font>
</c:if>
<form action="<c:url value="/admin/loginCheck.html"/>" method="post">
用户名:<input type="text" name="username">
<br>
密 码:<input type="password" name="password">
<br>
<input type="submit" value="登录"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
<%--
User: GeBron
Date: 2021/11/12 13:44
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>景区网站管理</title>
</head>
<body>
${user.username},欢迎您进入景区网站后台管理!
</body>
</html>
maven 打包,运行 Web 应用程序,访问 http://localhost:8080/SpringHello/admin/login.html 达到登录页面
登录成功页面