Spring py登陆模块(包含 记录登陆时间,记录ip,增加积分)

嘛基于最近的复习准备写个关于spring登陆模块的小程序 虽然小但是五脏俱全呐 话不多说让我来介绍一下今天的登陆程序、

这些是

  •   基于Spring JDBC 的持久层实现
  •   基于Spring 声明事物的业务层实现
  •   基于Spring MVC 的展示成实现
  •   在IDEA中开发的WEB应用过程

  它的功能呢很简单 就是让用户输入用户名和密码验证登陆 如果不正确就提示输入用户名/密码 错误

    如果正确那么就跳转相关页面 并且记录 当时的登陆时间和ip地址 和增加一次积分

   大概有个了解之后让我们准备环境 我演示这个案例的时候 使用的是JDK1.8+IDEA+maven+jetty

   具体在idea内搭建maven的方法可以去看看我这篇地址:这里我就不介绍了  我直接来说说prom.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.smart</groupId>
    <artifactId>LoginSpring</artifactId>
    <version>1.0</version>
    <name>滑稽</name>
    <description>滑稽</description>
    <packaging>war</packaging>
    <dependencies>
        <!-- spring 依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>${commons-dbcp.version}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>${servlet.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.17</version>
                <configuration>
                    <parallel>methods</parallel>
                    <threadCount>10</threadCount>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <file.encoding>UTF-8</file.encoding>
        <spring.version>4.2.2.RELEASE</spring.version>
        <mysql.version>5.1.29</mysql.version>
        <servlet.version>3.0-alpha-1</servlet.version>
        <aspectj.version>1.8.1</aspectj.version>
        <commons-codec.version>1.9</commons-codec.version>
        <commons-dbcp.version>1.4</commons-dbcp.version>
        <hibernate.validator.version>5.0.2.Final</hibernate.validator.version>
        <jetty.version>8.1.8.v20121106</jetty.version>
        <slf4j.version>1.7.5</slf4j.version>
        <testng.version>6.8.7</testng.version>
    </properties>
</project>

如果你需要在porm.xml中集成配置jetty的话 可以在plugins标签下写入这个

  

 <!-- jetty插件 -->
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.25</version>
                <configuration>
                    <connectors>
                        <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                            <port>8000</port>
                            <maxIdleTime>60000</maxIdleTime>
                        </connector>
                    </connectors>
                    <contextPath>/bbs</contextPath>
                    <scanIntervalSeconds>0</scanIntervalSeconds>
                </configuration>
            </plugin>

接下来是数据库表 一共我们需要两个表 一个“用户表”和一个“日志表”

  用户表记录用户 “ID,用户名,密码,积分,登陆时间,ip” 详情如下

##创建用户表
CREATE TABLE t_user (
   user_id   INT AUTO_INCREMENT PRIMARY KEY,
   user_name VARCHAR(30),
   PASSWORD  VARCHAR(32),
   credits INT,
   last_visit DATETIME,
   last_ip  VARCHAR(23)
)ENGINE=INNODB; 

日志表 关联着用户表的id 同时也包含 “ip,和时间” 详情如下

  

##创建用户登录日志表
CREATE TABLE t_login_log (
   login_log_id  INT AUTO_INCREMENT PRIMARY KEY,
   user_id   INT,
   ip  VARCHAR(23),
   login_datetime DATETIME
)ENGINE=INNODB; 

这个时候我们需要提前插入一组数据

  

##插入初始化数据
INSERT INTO t_user (user_name,PASSWORD)
             VALUES('admin','123456');

OK最基本的环境搭建成功了  提前预览一下包/测试包 的结构

Spring  py登陆模块(包含 记录登陆时间,记录ip,增加积分)

先从持久层说起它负责数据的访问和操作 为此我们需要知道一个东西 那就是“领域对象”可能有点陌生 但他还有宁外一个名字 "实体类"

在domain包类建立两个实体类 User 和LoginLog 他们都需要导入Serializable 序列化

  User表情况如下  实现Set Get 方法

    private int userId;

    private String userName;

    private String password;

    private int credits;

    private String lastIp;

    private Date lastVisit;

  LoginLog 如下

    private int loginLogId;

    private int userId;

    private String ip;

    private Date loginDate;

建立DAO类  先说说UserDao 它包含三个方法

  getMatchCount()  根据用户名和密码获取匹配的用户数,等于1表示“用户名/密码”正确 等于0 表示“用户名/密码不正确

  findUserByUserName() 根据用户名获取User对象

  updateLoginInfo() 更新用户积分 组后登陆ip 和时间

我们使用Spring 自带的JDBC封装方法

 package com.smart.dao;

package com.smart.dao;
import java.sql.ResultSet;
import java.sql.SQLException;

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 com.smart.domain.User;

@Repository
public class UserDao {
    private JdbcTemplate jdbcTemplate;

    private  final static String MATCH_COUNT_SQL = " SELECT count(*) FROM t_user  " +
            " WHERE user_name =? and password=? ";
    private  final static String UPDATE_LOGIN_INFO_SQL = " UPDATE t_user SET " +
            " last_visit=?,last_ip=?,credits=?  WHERE user_id =?";
  //根据用户名和密码获取匹配的用户数,等于1表示“用户名/密码”正确 等于0 表示“用户名/密码不正确 public int getMatchCount(String userName, String password) { return jdbcTemplate.queryForObject(MATCH_COUNT_SQL, new Object[]{userName, password}, Integer.class); }      //根据用户名获取User对象 public User findUserByUserName(final String userName) { String sqlStr = " SELECT user_id,user_name,credits " + " FROM t_user WHERE user_name =? "; final User user = new User(); jdbcTemplate.query(sqlStr, new Object[] { userName },
          //匿名类方式方法实现回调用函数 new RowCallbackHandler() { public void processRow(ResultSet rs) throws SQLException { user.setUserId(rs.getInt("user_id")); user.setUserName(userName); user.setCredits(rs.getInt("credits")); } }); return user; }   
  
   //更新用户积分 组后登陆ip 和时间  public void updateLoginInfo(User user) { jdbcTemplate.update(UPDATE_LOGIN_INFO_SQL, new Object[] { user.getLastVisit(), user.getLastIp(),user.getCredits(),user.getUserId()}); } @Autowired public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } }

接下来是 LoginLogDao  相较于UserDao 它的任务就很简单了 就一个更新就好了

package com.smart.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import com.smart.domain.LoginLog;

@Repository
public class LoginLogDao {
    private JdbcTemplate jdbcTemplate;

    //保存登陆日志SQL
    private final static String INSERT_LOGIN_LOG_SQL= "INSERT INTO " +
            " t_login_log(user_id,ip,login_datetime) VALUES(?,?,?)";

    public void insertLoginLog(LoginLog loginLog) {
        Object[] args = { loginLog.getUserId(), loginLog.getIp(),
                          loginLog.getLoginDate() };
        jdbcTemplate.update(INSERT_LOGIN_LOG_SQL, args);
    }

    @Autowired
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
}

接下来你需要在 spring中装配DAO 你必须在resources文件中新建一个spring的配置文件

  我的配置文件叫做 smart-context.xml  在里面配置如下

  

   <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
    <context:component-scan base-package="com.smart.dao"/>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="com.mysql.jdbc.Driver"
        p:url="jdbc:mysql://localhost:3306/xxxx"
        p:username="root"
        p:password="xxxx" />

    <!-- 配置Jdbc模板  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="dataSource" />
        

DAO在spring中的装配就已经完成  接下来我们需要写业务层

  它的作用就是将UserDao 和LoginLog组合起来 完成密码认证,登陆日志记录等操作

  

package com.smart.service;
/**
 *用户管理 userService COM.SMART.DAO
 * */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import com.smart.dao.LoginLogDao;
import com.smart.dao.UserDao;
import com.smart.domain.LoginLog;
import com.smart.domain.User;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {
    private UserDao userDao;
    private LoginLogDao loginLogDao;
    
  //登陆验证 public boolean hasMatchUser(String userName, String password) { int matchCount =userDao.getMatchCount(userName, password); return matchCount > 0; } public User findUserByUserName(String userName) { return userDao.findUserByUserName(userName); }   
  
   //事物注解 @Transactional public void loginSuccess(User user) { user.setCredits( 5 + user.getCredits()); LoginLog loginLog = new LoginLog(); loginLog.setUserId(user.getUserId()); loginLog.setIp(user.getLastIp()); loginLog.setLoginDate(user.getLastVisit()); userDao.updateLoginInfo(user); loginLogDao.insertLoginLog(loginLog); } @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Autowired public void setLoginLogDao(LoginLogDao loginLogDao) { this.loginLogDao = loginLogDao; } }

然后在spring中装配Service 还是打开smart-context.xml文件 添加内容

  

    <context:component-scan base-package="com.smart.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.smart.service..*(..))) and (@annotation(org.springframework.transaction.annotation.Transactional))" />
        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

现在我们需要做一个单元测试来测试一下我们的dao 和service的调配之间有没有问题

  test文件目录与java的结构一致 如下

Spring  py登陆模块(包含 记录登陆时间,记录ip,增加积分)

然后我们就开始测试

package com.smart.service;

import java.util.Date;
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
import org.testng.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import com.smart.domain.User;
import static org.testng.Assert.*;
//导入spring配置文件
@ContextConfiguration("classpath*:/smart-context.xml")
public class UserServiceTest extends AbstractTransactionalTestNGSpringContextTests {

    @Autowired
    private UserService userService;
  
  
  //测试用户名和密码 @Test public void testHasMatchUser() { boolean b1 = userService.hasMatchUser("admin", "123456"); boolean b2 = userService.hasMatchUser("admin", "1111"); assertTrue(b1); assertTrue(!b2); }   
  
  //还是一样的交易 @Test public void testFindUserByUserName()throws Exception{ for(int i =0; i< 100;i++) { User user = userService.findUserByUserName("admin"); assertEquals(user.getUserName(), "admin"); } }
@Test public void testAddLoginLog() { User user = userService.findUserByUserName("admin"); user.setUserId(1); user.setUserName("admin"); user.setLastIp("192.168.12.7"); user.setLastVisit(new Date()); userService.loginSuccess(user); } }

嘛 我们现在DAO和Service都有了 现在就需要展示层了

  第一步我们要配置Spring mvc 框架 首先 要去web.xml配置一下

  

<?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配置文件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:smart-context.xml</param-value>
    </context-param>

    <!--启动监听器-->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <!--配置由spring主控的servlet
    这意味着必须在WEB-INF目录下 提供一个为smart-servlet.xml 的spring mvc配置文件
    这里可以不用进行上下文参数声名 因为spring mvc的servlet会自动将其它配置文件比如
    smart-dao.xml smart-service 这类文件进行自我拼装-->
    <servlet>
        <servlet-name>smart</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>3</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>smart</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
</web-app>

为了满足处理登陆请求 我们还需要一个POJO控制器类 首先在 web目录下新建一个 LoginCommand类

这里的web是com.smart.web 不是有WEB-INF的那个web

  LoginCommand类 满足Set Get方法

  

    private String userName;

    private String password;

然后是LoginController控制器

package com.smart.web;

import java.util.Date;

import javax.servlet.http.HttpServletRequest;

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.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.smart.domain.User;
import com.smart.service.UserService;

//成为 spring mvc 的controller
@RestController
public class LoginController{
    private UserService userService;

    //负责处理/index.html的请求
    @RequestMapping(value = "/index.html")
    public String loginPage(){
        return "login";
    }

    //负责处理 loginCheck 的请求 请求参数会被绑到loginCommand 中
    @RequestMapping(value = "/loginCheck.html")
    public ModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){
        boolean isValidUser =  userService.hasMatchUser(loginCommand.getUserName(),
                                        loginCommand.getPassword());
        //如果用户名和密码有误 返回给前台的提示
        if (!isValidUser) {
            return new ModelAndView("login", "error", "用户名或密码错误。");
        } else {
            User user = userService.findUserByUserName(loginCommand
                    .getUserName());
            user.setLastIp(request.getLocalAddr());
            user.setLastVisit(new Date());
            userService.loginSuccess(user);
            request.getSession().setAttribute("user", user);
            return new ModelAndView("main");
        }
    }

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

写好后我们需要在smart-servlet.xml文件声明这个控制器 并且扫描web路径

  指定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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 扫描web包,应用Spring的注解 -->
<context:component-scan base-package="com.smart.web"/>

<!-- 配置视图解析器,将ModelAndView及字符串解析为具体的页面 -->
<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>

好了 我们去编写几个前台JSP页面 由于只做测试用 所以非常的简洁。。。

  login.jsp 登陆页面 别忘了文件位置是在WEB-INF/jsp 路径下 = - =

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ 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="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>

再来个欢迎 页面 main.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>小春论坛</title>
</head>
<body>
    ${user.userName},欢迎来到新♂暮♂里,您当前积分为${user.credits};
</body>
</html>

然后配置好jetty 启动就ok 了 如果是使用在porm集成配置jetty的同学 就在maven里面 启动

  Spring  py登陆模块(包含 记录登陆时间,记录ip,增加积分)

然后启动就去自己玩吧

小问题总结

  最后我说说 我在写代码的时候遇见的几个小问题=-= 第一个就是 区分Date 和 Data 别看 区别是屁股后面的一个e a 区别大了去 一个 是日期 一个是数据 妈蛋上次我就写错了

害得我错了好久。。。

  第二个就是 数据库语句拼串 如图

Spring  py登陆模块(包含 记录登陆时间,记录ip,增加积分)

第一段的屁股和第二段的开始 一定要 加空格 加空格 加空格 不然嘛 你就会体验到很脑残的错误。。。。。

    第三个就是导入包的问题 由于 这个问题存在与很多地方 就是好几种相同名字的包 你不知道导入那个2333 这个特别是有些方法的名字可能几个方法 都在用 所以一定要学会如何辨别导入包 2333

  第三个 就是编写测试类的时候 要注意 文件目录 和 extends AbstractTransactionalTestNGSpringContextTests 特别是 @Test 这个不是junit的 要注意

好了 这些就是我写这个登陆插件时候的所见所闻   = - = 有什么问题可以留言 

上一篇:C# @符号的多种使用方法


下一篇:15、C#基础整理(递归)