【Spring实战-1】网站登录系统

系统概述:

2015年5月8日 14:05:49 
本系统为一个常规的用户登录系统,主要完成了用户登录界面设计、用户登录后信息校验、更新用户登录信息以及记录用户登录信息等。
整个系统以Spring框架为基础来实现,项目构架时进行了分层设计,主要包括:持久层、业务层、控制层以及POJO(demain);
本系统使用的技术为:
1. 数据库:MySQL;
2. 数据库操作:Spring jdbc;
3. MVC框架,Spring MVC;
4. 容器:Spring容器;


涉及到的技术点:

1.  使用 JdbcTemplate 实现Mysql数据库的增、删、改、查操作;
2.  注解的使用:
     @Repository:注解持久层(dao)bean;
     @Service:注解业务层bean;
     @Controller:展现层(控制层)bean,标注为Spring mvc的控制器;
     @Autowired:将Spring容器中的bean注入进来;
     @ContextConfiguration:指定Spring配置文件的位置;
     @RequestMapping:指定如何映射请求地址;

3. RowCallbackHandler:查询结果处理的回调接口,实现ResultSet到POJO对象的转换;

4. 事务管理器:为数据库操作实现事务;

5. 引入shema命名空间:
  p: 用于简化类的成员变量;
  tx:
 aop:

6. 利用junit进行测试;

7. 配置Spring容器:配置Spring容器所必须的两个参数(web.xml)

  1. <!-- 从类路径下加载Spring配置文件,classpath关键字特指从类路径下加载 -->
  2. <context-param>
  3. <param-name>contextConfigLocation</param-name>
  4. <param-value>classpath:applicationContext.xml</param-value>
  5. </context-param>
  6. <!-- 负责启动Spring容器的监听器 -->
  7. <listener>
  8. <listener-class>
  9. org.springframework.web.context.ContextLoaderListener
  10. </listener-class>
  11. </listener>



8. 配置Spring MVC:(web.xml)
  1. <!-- 配置Spring MVC,其对应的配置文件为:servlet-name-servlet.xml,
  2. 本项目的为:baobaotao-servlet.xml -->
  3. <servlet>
  4. <servlet-name>baobaotao</servlet-name>
  5. <servlet-class>
  6. org.springframework.web.servlet.DispatcherServlet
  7. </servlet-class>
  8. <load-on-startup>3</load-on-startup>
  9. </servlet>
  10. <servlet-mapping>
  11. <servlet-name>baobaotao</servlet-name>
  12. <url-pattern>*.html</url-pattern>
  13. </servlet-mapping>

9. Spring声明式事务;
这个以后在具体介绍。

项目整体布局

项目整体布局:
 
主要包括src和test,其中test为junit测试类,主要用于测试业务层;

使用的jar包

下面是配置文件及前端界面等;


Mysql数据库指令

  1. DROP DATABASE IF EXISTS sampledb;
  2. CREATE DATABASE sampledb DEFAULT CHARACTER SET utf8;
  3. USE sampledb;
  4. ##创建用户表
  5. CREATE TABLE t_user (
  6. user_id INT AUTO_INCREMENT PRIMARY KEY,
  7. user_name VARCHAR(30),
  8. credits INT,
  9. password VARCHAR(32),
  10. last_visit datetime,
  11. last_ip VARCHAR(23)
  12. )ENGINE=InnoDB;
  13. ##创建用户登录日志表
  14. CREATE TABLE t_login_log (
  15. login_log_id INT AUTO_INCREMENT PRIMARY KEY,
  16. user_id INT,
  17. ip VARCHAR(23),
  18. login_datetime datetime
  19. )ENGINE=InnoDB;
  20. ##插入初始化数据
  21. INSERT INTO t_user (user_name,password)
  22. VALUES('admin','123456');
  23. COMMIT;

上述指令执行完成后,在Mysql创建的情况如下:




源程序

com.baobaotao.domain包:定义POJO对象

LoginLog.java

  1. package com.baobaotao.domain;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. public class LoginLog implements Serializable{
  5. private int loginLogId;
  6. private int userId;
  7. private String ip;
  8. private Date loginDate;
  9. public String getIp() {
  10. return ip;
  11. }
  12. public void setIp(String ip) {
  13. this.ip = ip;
  14. }
  15. public Date getLoginDate() {
  16. return loginDate;
  17. }
  18. public void setLoginDate(Date loginDate) {
  19. this.loginDate = loginDate;
  20. }
  21. public int getLoginLogId() {
  22. return loginLogId;
  23. }
  24. public void setLoginLogId(int loginLogId) {
  25. this.loginLogId = loginLogId;
  26. }
  27. public int getUserId() {
  28. return userId;
  29. }
  30. public void setUserId(int userId) {
  31. this.userId = userId;
  32. }
  33. }



User.java

  1. package com.baobaotao.domain;
  2. import java.io.Serializable;
  3. import java.util.Date;
  4. public class User implements Serializable{
  5. private int userId;
  6. private String userName;
  7. private String password;
  8. private int credits;
  9. private String lastIp;
  10. private Date lastVisit;
  11. public String getLastIp() {
  12. return lastIp;
  13. }
  14. public void setLastIp(String lastIp) {
  15. this.lastIp = lastIp;
  16. }
  17. public Date getLastVisit() {
  18. return lastVisit;
  19. }
  20. public void setLastVisit(Date lastVisit) {
  21. this.lastVisit = lastVisit;
  22. }
  23. public int getUserId() {
  24. return userId;
  25. }
  26. public void setUserId(int userId) {
  27. this.userId = userId;
  28. }
  29. public String getUserName() {
  30. return userName;
  31. }
  32. public void setUserName(String userName) {
  33. this.userName = userName;
  34. }
  35. public String getPassword() {
  36. return password;
  37. }
  38. public void setPassword(String password) {
  39. this.password = password;
  40. }
  41. public int getCredits() {
  42. return credits;
  43. }
  44. public void setCredits(int credits) {
  45. this.credits = credits;
  46. }
  47. }

com.baobaotao.dao包

LoginLogDao.java

  1. package com.baobaotao.dao;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.jdbc.core.JdbcTemplate;
  4. import org.springframework.stereotype.Repository;
  5. import com.baobaotao.domain.LoginLog;
  6. @Repository
  7. public class LoginLogDao {
  8. @Autowired
  9. private JdbcTemplate jdbcTemplate;
  10. /**
  11. * 插入登录信息
  12. * @param loginLog
  13. */
  14. public void insertLoginLog(LoginLog loginLog) {
  15. String sqlStr = "INSERT INTO t_login_log(user_id,ip,login_datetime) "
  16. + "VALUES(?,?,?)";
  17. Object[] args = { loginLog.getUserId(), loginLog.getIp(),
  18. loginLog.getLoginDate() };
  19. jdbcTemplate.update(sqlStr, args);
  20. }
  21. }


UserDao.java

  1. package com.baobaotao.dao;
  2. import java.sql.ResultSet;
  3. import java.sql.SQLException;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.jdbc.core.JdbcTemplate;
  6. import org.springframework.jdbc.core.RowCallbackHandler;
  7. import org.springframework.stereotype.Repository;
  8. import com.baobaotao.domain.User;
  9. @Repository
  10. public class UserDao {
  11. @Autowired
  12. private JdbcTemplate jdbcTemplate;
  13. /**
  14. * 获取匹配的用户数量
  15. * @param userName
  16. * @param password
  17. * @return
  18. */
  19. public int getMatchCount(String userName, String password) {
  20. String sqlStr = " SELECT count(*) FROM t_user "
  21. + " WHERE user_name =? and password=? ";
  22. return jdbcTemplate.queryForInt(sqlStr, new Object[] { userName, password });
  23. }
  24. /**
  25. * 查询用户
  26. * @param userName
  27. * @return
  28. */
  29. public User findUserByUserName(final String userName) {
  30. String sqlStr = " SELECT user_id,user_name,credits "
  31. + " FROM t_user WHERE user_name =? ";
  32. final User user = new User();
  33. jdbcTemplate.query(sqlStr, new Object[] { userName },
  34. new RowCallbackHandler() {
  35. public void processRow(ResultSet rs) throws SQLException {
  36. user.setUserId(rs.getInt("user_id"));
  37. user.setUserName(userName);
  38. user.setCredits(rs.getInt("credits"));
  39. }
  40. });
  41. return user;
  42. }
  43. /**
  44. * 更新登录信息
  45. * @param user
  46. */
  47. public void updateLoginInfo(User user) {
  48. String sqlStr = " UPDATE t_user SET last_visit=?,last_ip=?,credits=? "
  49. + " WHERE user_id =?";
  50. jdbcTemplate.update(sqlStr, new Object[] { user.getLastVisit(),
  51. user.getLastIp(),user.getCredits(),user.getUserId()});
  52. }
  53. }



com.baobaotao.service包

UserService.java

  1. package com.baobaotao.service;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.stereotype.Service;
  4. import com.baobaotao.dao.LoginLogDao;
  5. import com.baobaotao.dao.UserDao;
  6. import com.baobaotao.domain.LoginLog;
  7. import com.baobaotao.domain.User;
  8. @Service
  9. public class UserService {
  10. @Autowired
  11. private UserDao userDao;
  12. @Autowired
  13. private LoginLogDao loginLogDao;
  14. /**
  15. * 是否有匹配的用户
  16. * @param userName
  17. * @param password
  18. * @return
  19. */
  20. public boolean hasMatchUser(String userName, String password) {
  21. int matchCount =userDao.getMatchCount(userName, password);
  22. return matchCount > 0;
  23. }
  24. /**
  25. * 根据用户名查找用户
  26. * @param userName
  27. * @return
  28. */
  29. public User findUserByUserName(String userName) {
  30. return userDao.findUserByUserName(userName);
  31. }
  32. /**
  33. * 登录成功时,更新登录信息并添加登录记录
  34. * @param user
  35. */
  36. public void loginSuccess(User user) {
  37. user.setCredits( 5 + user.getCredits()); //信用加5
  38. LoginLog loginLog = new LoginLog();
  39. loginLog.setUserId(user.getUserId());
  40. loginLog.setIp(user.getLastIp());
  41. loginLog.setLoginDate(user.getLastVisit());
  42. userDao.updateLoginInfo(user);
  43. loginLogDao.insertLoginLog(loginLog);
  44. }
  45. }


com.baobaotao.web包

LoginCommand.java

  1. package com.baobaotao.web;
  2. public class LoginCommand {
  3. private String userName;
  4. private String password;
  5. public String getPassword() {
  6. return password;
  7. }
  8. public void setPassword(String password) {
  9. this.password = password;
  10. }
  11. public String getUserName() {
  12. return userName;
  13. }
  14. public void setUserName(String userName) {
  15. this.userName = userName;
  16. }
  17. }


LoginController.java

  1. package com.baobaotao.web;
  2. import java.util.Date;
  3. import javax.servlet.http.HttpServletRequest;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.servlet.ModelAndView;
  8. import com.baobaotao.domain.User;
  9. import com.baobaotao.service.UserService;
  10. @Controller
  11. public class LoginController{
  12. @Autowired
  13. private UserService userService;
  14. @RequestMapping(value = "/index.html")
  15. public String loginPage(){
  16. return "login";
  17. }
  18. @RequestMapping(value = "/loginCheck.html")
  19. public ModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){
  20. boolean isValidUser =
  21. userService.hasMatchUser(loginCommand.getUserName(),
  22. loginCommand.getPassword());
  23. if (!isValidUser) {
  24. return new ModelAndView("login", "error", "用户名或密码错误。");
  25. } else {
  26. User user = userService.findUserByUserName(loginCommand
  27. .getUserName());
  28. user.setLastIp(request.getLocalAddr());
  29. user.setLastVisit(new Date());
  30. userService.loginSuccess(user);
  31. request.getSession().setAttribute("user", user);
  32. return new ModelAndView("main");
  33. }
  34. }
  35. }

说明:
在mvc架构中,model和view是松耦合的,控制层负责产生model数据,而view负责渲染模型数据。
request.getSession().setAttribute("user", user);
return new ModelAndView("main");
等价于:
ModelAndView("main", "user", user);




web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.5"
  3. xmlns="http://java.sun.com/xml/ns/javaee"
  4. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  6. http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  7. <!-- 从类路径下加载Spring配置文件,classpath关键字特指从类路径下加载 -->
  8. <context-param>
  9. <param-name>contextConfigLocation</param-name>
  10. <param-value>classpath:applicationContext.xml</param-value>
  11. </context-param>
  12. <!-- 负责启动Spring容器的监听器 -->
  13. <listener>
  14. <listener-class>
  15. org.springframework.web.context.ContextLoaderListener
  16. </listener-class>
  17. </listener>
  18. <!-- 配置Spring MVC,其对应的配置文件为:servlet-name-servlet.xml,
  19. 本项目的为:baobaotao-servlet.xml -->
  20. <servlet>
  21. <servlet-name>baobaotao</servlet-name>
  22. <servlet-class>
  23. org.springframework.web.servlet.DispatcherServlet
  24. </servlet-class>
  25. <load-on-startup>3</load-on-startup>
  26. </servlet>
  27. <servlet-mapping>
  28. <servlet-name>baobaotao</servlet-name>
  29. <url-pattern>*.html</url-pattern>
  30. </servlet-mapping>
  31. </web-app>

说明:
web.xml中,contextConfigLocation和ContextLoaderListener是使用Spring容器必须配置的;
而DispatcherServlet是使用Spring MVC所必须的。




Spring配置文件

applicationContext.xml
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context-3.0.xsd
  10. http://www.springframework.org/schema/tx
  11. http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  12. http://www.springframework.org/schema/aop
  13. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  14. <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
  15. <context:component-scan base-package="com.baobaotao.dao"/>
  16. <context:component-scan base-package="com.baobaotao.service"/>
  17. <!-- 配置数据源 -->
  18. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
  19. destroy-method="close"
  20. p:driverClassName="com.mysql.jdbc.Driver"
  21. p:url="jdbc:mysql://localhost:3306/sampledb"
  22. p:username="root"
  23. p:password="xxx" />
  24. <!-- 配置Jdbc模板 -->
  25. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
  26. p:dataSource-ref="dataSource" />
  27. <!-- 配置事务管理器 -->
  28. <bean id="transactionManager"
  29. class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
  30. p:dataSource-ref="dataSource" />
  31. <!-- 通过AOP配置提供事务增强,让service包下所有Bean的所有方法拥有事务 -->
  32. <aop:config proxy-target-class="true">
  33. <aop:pointcut id="serviceMethod"
  34. expression=" execution(* com.baobaotao.service..*(..))" />
  35. <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
  36. </aop:config>
  37. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  38. <tx:attributes>
  39. <tx:method name="*" />
  40. </tx:attributes>
  41. </tx:advice>
  42. </beans>

说明:
上述配置文件中,使用了schema来简化配置。如:<p:...>、<tx:...>、<aop:...>;
组件扫描:<context:component>扫描标记了@Controller、@Service、@Repository的类,自动为这些类创建bean。


Spring MVC配置文件

baobaotao-servlet.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  9. <!-- 扫描web包,应用Spring的注解 -->
  10. <context:component-scan base-package="com.baobaotao.web"/>
  11. <!-- 配置视图解析器,将ModelAndView及字符串解析为具体的页面 -->
  12. <bean
  13. class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  14. p:viewClass="org.springframework.web.servlet.view.JstlView"
  15. p:prefix="/WEB-INF/jsp/"
  16. p:suffix=".jsp" />
  17. </beans>

说明:
这是配置了InternalResourceViewResolver视图解析器。Spring MVC中的视图解析器有好多种,且每种视图解析器都可以设置优先级。InternalResourceViewResolver视图解析器只是最常用且最普通的一种视图解析器,它的默认优先级是最低的。



前端jsp界面

login.jsp

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  4. <html>
  5. <head>
  6. <title>论坛登录</title>
  7. </head>
  8. <body>
  9. <c:if test="${!empty error}">
  10. <font color="red"><c:out value="${error}" /></font>
  11. </c:if>
  12. <form action="<c:url value="loginCheck.html"/>" method="post">
  13. 用户名:
  14. <input type="text" name="userName">
  15. <br>
  16. 密 码:
  17. <input type="password" name="password">
  18. <br>
  19. <input type="submit" value="登录" />
  20. <input type="reset" value="重置" />
  21. </form>
  22. </body>
  23. </html>

说明:
这里使用了jstl标签,<c:url value="loginCheck.html"/>的jstl标签会在url前自动加上应用程序的部署根目录,假设应用程序部署在bbt目录下,<c:url/>标签将输出:/bbt/loginCheck.html 。通过<c:url />标签,很好的解决了开发和应用部署目录不一致的问题。

main.jsp

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  4. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  8. <title>论坛</title>
  9. </head>
  10. <body>
  11. ${user.userName},欢迎您进入宝宝淘论坛,您当前积分为${user.credits};
  12. </body>
  13. </html>


log4j.properties

  1. log4j.rootLogger=DEBUG,A1
  2. log4j.appender.A1=org.apache.log4j.ConsoleAppender
  3. log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  4. log4j.appender.A1.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n

程序测试

在tomcat下运行该系统,在浏览器中输入:http://localhost:8080/LoginProj/loginCheck.html ,
用户名密码输入错误时:

用户名密码输入正确时:

下面是数据库信息:




Junit测试

com.baobaotao.service包:TestUserService.java
  1. package com.baobaotao.service;
  2. import static org.junit.Assert.*;
  3. import java.util.Date;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.test.context.ContextConfiguration;
  8. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  9. import com.baobaotao.domain.User;
  10. @RunWith(SpringJUnit4ClassRunner.class)
  11. @ContextConfiguration(locations={"classpath:applicationContext.xml"})
  12. public class TestUserService {
  13. @Autowired
  14. private UserService userService;
  15. @Test
  16. public void testHasMatchUser() {
  17. boolean b1 = userService.hasMatchUser("admin", "123456");
  18. boolean b2 = userService.hasMatchUser("admin", "1111");
  19. assertTrue(b1);
  20. assertTrue(!b2);
  21. }
  22. @Test
  23. public void testFindUserByUserName() {
  24. User user = userService.findUserByUserName("admin");
  25. assertEquals(user.getUserName(), "admin");
  26. }
  27. @Test
  28. public void testAddLoginLog() {
  29. User user = userService.findUserByUserName("admin");
  30. user.setUserId(1);
  31. user.setUserName("admin");
  32. user.setLastIp("192.168.12.7");
  33. user.setLastVisit(new Date());
  34. userService.loginSuccess(user);
  35. }
  36. }


测试结果如下:



至此,整个系统全部完成。












附件列表

    原文地址:https://www.cnblogs.com/ssslinppp/p/4487552.html