千家信息网

Spring3.0第三讲:Spring实现简单的登录

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,学习Spring这些技术性框架,光掌握理论知识是远远不够了,我们要懂得学以致用,用键盘将学到的敲出来,在正确与错误中寻找Spring的用法。为了给读者一个直观的概念,这里我用Spring搭建一个简单的
千家信息网最后更新 2026年10月31日Spring3.0第三讲:Spring实现简单的登录

学习Spring这些技术性框架,光掌握理论知识是远远不够了,我们要懂得学以致用,用键盘将学到的敲出来,在正确与错误中寻找Spring的用法。

为了给读者一个直观的概念,这里我用Spring搭建一个简单的登录,可以让你很快的了解Spring在持久层、业务层、表现层是怎么运作的,这样后面我们分模块讲解的时候,读者也能很快的知道。

本文所用工具为Eclipse IDE,数据库为Oracle 11g。

首先我们来了解登录这个功能,用户访问登录页面,输入账号和密码,点击登录,后台验证是否有账号和密码匹配,如果匹配成功,则跳到欢迎页面,并显示用户积分,如果登录失败则返回登录页面,并提示登录失败信息。

简化图:

有经验的程序员知道在开发之前都会先写开发设计或者画类图,这里面笔者也从开发设计开始,针对登录的全过程先设计好再开发,毕竟磨刀不误砍材功。

上面是登录功能设计的全部过程大致描述一下:

1.首先访问login.jsp,返回可输入用户账号以及密码的表单登录页面

2.用户在登录页面输入账号、密码,提交表单到服务器,Spring根据配置调用LoginController控制器响应请求。

3.LoginController调用LoginService/isExistUser方法,根据传递的用户、密码参数查询是否存在用户,LoginService内部通过持久层LoginDao与数据进行交互。

4.如果匹配不到用户,则返回Login.jsp,并返回提示信息,如果匹配成功,则进入下一步。

5.LoginController调用LoginService/findUserByUsername获取当前登录人的实体,设置当前登录时间以及积分更新后的值。

6.LoginController调用LoginService/loginsuccess()方法,进行登录成功后的业务处理,首先更新用户信息,以及创建LoginInfo日志对象并插入数据库。

7.重定向欢迎页面welcome.jsp页面,并返回响应。

环境准备:

1.表创建

create table TB_USER   --用户表(  userid          VARCHAR2(20),  username        VARCHAR2(20),  credits         NUMBER,  password        VARCHAR2(100),  last_login_time DATE,  last_login_ip   VARCHAR2(30))create table TB_LOGIN_LOG --用户登录日志(  login_id      VARCHAR2(20),  login_user_id VARCHAR2(20),  ip            VARCHAR2(20),  login_time    DATE)--插入一条用户insert into tb_user (USERID, USERNAME, CREDITS, PASSWORD, LAST_LOGIN_TIME, LAST_LOGIN_IP)values ('zhangsan', '张三', 0, '123456', to_date('06-07-2016 09:10:39', 'dd-mm-yyyy hh34:mi:ss'), '0:0:0:0:0:0:0:1');

2.建立工程

良好的包分类以及分层会给维护以及其他开发带来的很大的好处,一般企业项目中包的分类还应该按项目模块分,本文的项目较简单,因此分类就简单化,同时对于Spring 的配置文件一般都会有文件夹存放,这里我们就不详细说明,相信读者在工作中看到的项目大多数都是结构良好的。

关于Spring3.0相关jar,这里面读者可以自己去下载。

3.创建实体类

我们可以认为实体类是贯穿业务层、持久层、表现层的一条线,一个功能模块往往是围绕一个实体类,业务层修改实体类状态,持久层将实体类存储到数据库,表现层展现实体类的状态,可见实体类的重要性。

public class User {         private String userid;//用户ID         private String username;//用户姓名         private Integer credits;//积分         private String password;//密码         private Date lastlogintime;//最后登录时间         private String loginip;//最后登录ip         }public class LoginInfo {    private String loginid;//登录主键    private String loginuserid;//登录人ID    private String loginip;//登录IP    private Date logintime;//登录时间    }......省略get、set方法

4.持久层LoginDao与LoginLogDao

我们先看看关于操作User的DAO,主要包括3个方法

1.getUserCount(),返回结果为×××,如果返回1,则表示用户、密码匹配正确,返回0则表示用户、密码匹配错误,实际中这里存在密码加密解密功能,这里我们简单化。

2.findUserByUsername(),根据用户账号获取User实体。

3.updateUserInfo(),更新用户最后登录时间、 积分以及用户IP.

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 domain.User;@Repository //通过Spring注解定义一个Daopublic class LoginDao {         @Autowired//自动注入id为JdbcTemplate的bean     private JdbcTemplate jdbcTemplate;      /**      *        * @author zangyn       * @date 2016-8-19 下午1:54:16       * @Title: getUserCount       * @Description: 根据账号、密码匹配是否存在       * @return int    返回类型       * @throws      */     public int getUserCount(String username,String password){             String sql="SELECT COUNT(*) FROM TB_USER U WHERE U.USERID=? AND U.PASSWORD=?";                 int count=jdbcTemplate.queryForInt(sql,new Object[]{username,password});             return count;        }        /**         *           * @author zangyn          * @date 2016-8-19 下午1:54:43          * @Title: findUserByUsername          * @Description: 根据Userid查询是否存在该User          * @return User    返回类型          * @throws         */        public User findUserByUsername(String userid){                String sql="SELECT * FROM TB_USER U WHERE U.USERID=?";                final User u=new User();                jdbcTemplate.query(sql, new Object[]{userid}, new RowCallbackHandler() {                                                @Override                        public void proce***ow(ResultSet rs) throws SQLException {                                u.setUserid(rs.getString("userid"));                                u.setUsername(rs.getString("username"));                                 u.setCredits(rs.getInt("credits"));                        }                });                return u;        }        /**         *           * @author zangyn          * @date 2016-8-19 下午1:55:28          * @Title: updateUserInfo          * @Description: 更新用户相关信息          * @return void    返回类型          * @throws         */                public void updateUserInfo(User user){                String sql="UPDATE TB_USER U SET U.LAST_LOGIN_TIME=?,U.LAST_LOGIN_IP=?,U.CREDITS=? WHERE U.USERID=?";                jdbcTemplate.update(sql, new Object[]{user.getLastlogintime(),user.getLoginip(),user.getCredits(),user.getUserid()});        }}

Spring2.5以后,可以使用注解的方式定义Bean,相比较XML配置,注解配置简单太多,所以我们尽量要以注解为主进行Bean配置。

这里我们用@Repository定义了Dao bean的配置,使用 @Autowired将容器的Bean注入进来。

从上面可以看到关于数据库操作,我们引入了Spring JdbcTemplate,用过原始JDBC的都知道,在执行数据库操作之前都需要经过:获取连接>创建Statement>执行数据库操作>获取结果>关闭Statement>关闭结果集>关闭连接,同时我们还要关注异常的处理,每次执行sql,我们的1/3代码都重复的写以上的代码,对于以上样板式的代码,Spring JDBC进行了薄层的封装,将样板式的代码进行了封装,用户只需要编写那些必不可少的代码。

关于拼写SQL注意:在拼写较长的sql时,我们经常需要换行,由于上下行最终会转换为一个sql,这时候如果在每行的末尾没有空格,就会存在连在一起的情况,因此,良好的拼写SQL方法是在每行开始和结尾都打一个空格。

关于JdbcTemplate各种方法运用,我会在后面一篇详细介绍。

LoginLogDao只有一个存放日志记录的方法,代码如下:

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;import domain.LoginInfo;@Repository //通过Spring注解定义一个Daopublic class LoginLogDao {                @Autowired//自动注入id为JdbcTemplate的bean     private JdbcTemplate jdbcTemplate;         public void insertLoginfo(LoginInfo info){                 String sql="INSERT INTO TB_LOGIN_INFO(LOGIN_ID,LOGIN_USER_ID,IP,LOGIN_TIME) VALUES(login_info_seq.nextval,?,?,?)";                 Object[] obj=new Object[]{info.getLoginuserid(),info.getLoginip(),info.getLogintime()};                 jdbcTemplate.update(sql, obj);         }}

5.数据源配置以及Spring 加载Dao

在src下创建一个名为applicationContext.xml的文件,配置文件内容如下:

                                                                                     

Spring的扫描指定包下的类,这样@Repository、@Autowired注解才能起作用。

关于数据源配置这里只存在不同的配置源问题,关于为什么要这么配置,只能说是JDBC规范要求。

jdbcTemplate这个bean将dataSource注入到JdbcTemplate,然后JdbcTemplate Bean通过@Autowired注入到LoginLogDao和LoginDao中。

6. 服务层 LoginService

loginservice接口有三个方法:isExistUser用于验证账号、密码正确性、findUserByUsername用于根据用户账号加载User实体、loginSuccess用于登录成功进行积分变更、日志插入操作,这里存在事务操作,更新tb_user并插入tb_login_info,但是我们却没看到关于事务控制的代码,Spring的一大优点就是将事务从代码中解放出来,下面我会讲解关于Spring处理事务能力。

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import dao.LoginDao;import dao.LoginLogDao;import domain.LoginInfo;import domain.User;@Service //将LoginServcie标注为一个服务层Beanpublic class LoginService {        @Autowired        private LoginDao logindao;        @Autowired        private LoginLogDao loginlogdao;          public boolean isExistUser(String userid,String password){          int count=logindao.getUserCount(userid, password);          return count>0;  }  public User findUserByUsername(String userid){          return logindao.findUserByUsername(userid);  }   public void loginSuccess(User u){          u.setCredits(u.getCredits()+5);          LoginInfo info=new LoginInfo();          info.setLoginuserid(u.getUserid());          info.setLogintime(u.getLastlogintime());          info.setLoginip(u.getLoginip());          loginlogdao.insertLoginfo(info);          logindao.updateUserInfo(u);  }}

7.Spring加载Service

Spring的事务虽然不用出现在代码中,但是我们需要告诉Spring哪些业务类需要工作于事务环境以及事务的规则等内容,让Spring根据这些信息自动为目标业务类添加事务管理功能。

                                                                                                                                                                                                                        

关于业务层和配置已经完成,我们先单元测试一下。

8.单元测试

Spring 3.0的测试框架可以和Junit4整合,通过@RunWith可以指定SpringJUnit4Cla***unner测试运行器,该运行器是Spring提供的,可以将Spring容器和Junit4测试框架结合。@ContextConfiguration也是Spring提供的注解,用于指定Spring配置文件。@Test用于将方法标注为测试方法,

import static org.junit.Assert.*;import java.util.Date;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4Cla***unner;import domain.User;import service.LoginService;@RunWith(SpringJUnit4Cla***unner.class)//基于JUnit4的Spring测试框架@ContextConfiguration(locations={"classpath:applicationContext.xml"})//启动spring容器public class TestUserService {        @Autowired//注入spring容器bean        private LoginService loginservice;        @Test        public void isExistUser() {                boolean a1=loginservice.isExistUser("zhangsan", "123456");                boolean a2=loginservice.isExistUser("zhangsan", "1");                assertTrue(a1);                assertTrue(!a2);        }        @Test        public void findUserbyUsername() {                User u=loginservice.findUserByUsername("zhangsan");                assertEquals(u.getUserid(), "zhangsan");        }                @Test        public void loginSuccess(){                User u=new User();                u.setUserid("zhangsan");                u.setCredits(0);                u.setLoginip("127.0.0.1");                u.setLastlogintime(new Date());                loginservice.loginSuccess(u);        }}

9.配置SpringMVC

业务层以及持久层已经完成,现在我们需要用SpringMVC将展现层加入个整个功能里。首先对web.xml进行配置

contextConfigLocationclasspath:applicationContext.xml        org.springframework.web.context.ContextLoaderListenerSpringorg.springframework.web.servlet.DispatcherServlet            contextConfigLocation        classpath:Spring-servlet.xml     1  Spring*.html

web容器通过上下文参数指定Spring配置文件,多个配置文件可用逗号分开,然后web容器在启动的时候会自动启动监听器ContextLoaderListener,该监听器的作用是获取Spring配置文件并启动Spring容器,注意将log4j.properties放在类路径下,以便日志引擎生效。

SpringMVC也是通过截获URL请求,然后进行相关处理。

这里面注意SpringMVC也有个配置文件,该配置文件的文件与这里定义的Servlet名有一个契约,即

采用-servlet.xml,在这里Servlet的名称为Spring,意思是/WEB-INF下必须有个Spring-servlet.xml的配置文件,这个配置文件无需通过web.xml的上下文进行配置,SpringMVC的Servlet会自动将Spring-servlet.xml与其他配置文件拼装。

contextConfigLocation

classpath:Spring-servlet.xml

这里如果配置这个参数则配置文件就不会去执行上面的契约去查找Spring-servlet,会根据我们自己配置的文件查找。

Servlet的URL路径进行定义我们让所有后缀以.html的URL都能被Spring Servlet截获,然后转给SpringMVC进行处理,请求被SpringMVC接受后,首先根据URL找到目标的处理控制器,并将请求参数封装成一个"命令"对象一起传给控制器处理,控制器调用Spring 的业务Bean进行处理并返回视图。

10.控制器类LoginController

LoginController负责处理登录请求,完成登录业务,根据登录结果返回不同页面。

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.servlet.ModelAndView;import domain.LoginCommand;import domain.User;import service.LoginService;@Controllerpublic class LoginController {        @Autowired        private LoginService loginservice;                @RequestMapping(value="/index.html")        public String loginPage(){                return "login";        }        @RequestMapping(value="/loginCheck.html")        public ModelAndView loginCheck(HttpServletRequest request,LoginCommand loginCommand){                boolean isValid=loginservice.isExistUser(loginCommand.getUserid(), loginCommand.getPassword());                if(!isValid){                        return  new ModelAndView("login","error","用户或密码错误");                }else{                        User user=loginservice.findUserByUsername(loginCommand.getUserid());                        user.setLoginip(request.getRemoteAddr());                        user.setLastlogintime(new Date());                        request.getSession().setAttribute("user", user);                        loginservice.loginSuccess(user);                        return new ModelAndView("welcome");                }        }}

@Controller将LoginController标注为SpringMVC控制器,处理HTTP请求,一个控制器包含多个HTTP请求路径的处理方法,通过@RequestMapping指定方法映射请求路径。

请求参数会根据参数名称默认契约自动绑定到响应方法的入参中,在loginCheck(HttpServletRequest request,LoginCommand loginCommand),请求参数会根据名称匹配绑定到loginCommand中。

public class LoginCommand {        private String userid;//用户id        private String password;//用户密码        省略get/set        }

请求方法可以返回ModelAndView或者字符串,SpringMVC会解析并自动转向目标响应页面。关于ModelAndView读者只需知道它目前代表一种视图就行,后面会解释。

现在需要知道ModelAndView返回的两种形式,ModelAndView("login","error","用户或密码错误")和ModelAndView("main"),第一个参数代表视图的逻辑名,第二个以及第三个代表数据模型名称和数据模型对象,数据模型对象将以数据模型名称为参数名放置到request属性中。

SpringMVC的配置文件Spring-servlet.xml

                                

上面SpringMVC通过配置来解析ModelAndView,Spring有许多解析ModelAndView的方式,这里我们用InternalResourceViewResolver,它通过添加前后缀方式来解析。如ModelAndView("welcome"),将解析为/WEB-INF/login/welcome.jsp

11.JSP页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>论坛登录
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>论坛主页${user.username},欢迎你进入本论坛,你的积分为${user.credits}.

这里我引入c标签,需要引入两个jar包。

剩下的可以直接部署了,然后访问http://localhost:8088/项目部署名称/,输入zhangsan、123456即可登录成功。

配置 登录 用户 文件 密码 方法 数据 处理 业务 实体 页面 代码 参数 事务 账号 控制 容器 控制器 注解 测试 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 手冲咖啡和咖啡机区别 广州淘业互联网络科技 互联网科技有限公司经营范围 天下捷融互联网科技 济南和联互联网科技有限公司 开启互联网科技时代小说 欧洲十大科技互联网公司 互联网系的金融科技公司 互联网科技教育视频 广州恒生互联网科技有限 宁夏众和广鑫互联网科技有限公司 科技互联网大厂 语蝶互联网科技有限公司 互联网科技扶贫时间 佛山市翊博互联网络科技有限公司 互联网金融科技名词解释 科技赋能视角下互联网保险发展 广州千川互联网科技有限公司 互联网安防科技感 互联网科技创新方面的资料 手磨咖啡 上海挚品互联网科技有限公司 中关村互联网 科技集团 浩特互联网科技 老年人脱离互联网科技的作文 互联网和黑科技的看法 河南猎农互联网科技有限公司 四川慕妮娅互联网科技有限公司 中国互联网公司的科技投入 宁波允成互联网科技有限公司
0