spring快速入门案例

spring快速入门案例:

案例名称“宝宝淘”论坛的登录模块,功能虽小,但是五脏俱全,而且登录业务大家熟悉,不难理解。

首页登录页面提供一个输入表单,输入用户名和密码,用户填写并提交表单后,服务端程序检查是否有匹配的用户名和密码。
如果不匹配返回登录页面并给出提示;如果匹配记录用户的成功登陆日志,更新用户的最后登录时间和ip,并给用户增加5个积分,然后重定向到欢迎页面。

在这里插入图片描述

分析:

持久层需要2个dao,分别是UserDaoLoginLogDao,在业务层对应一个业务类UserService,在展现层有一个LoginController类,和2个jsp页面,分别是登录页面login.jsp和欢迎页面main.jsp

时序图

下面通过时序图描述登录模块的整体交互流程:
在这里插入图片描述
1、首先用户访问login.jsp,返回带用户名、密码表单的登录页面
2、用户在登录页面输入用户名、密码,提交表单到服务器,spring根据配置调用LoginController控制器响应登录请求
3、LoginController调用UserService#hasMatchUser()方法,根据用户名和密码查询是否存在匹配用户,UserService内部调用持久层的UserDao完成具体数据库访问操作
4、如果不存在匹配用户,重定向到login.jsp页面,并报告错误,否则到下一步
5、LoginController调用UserServicce#findUserByUserName()方法,加载匹配的User对象并更新用户最近一次登录时间和登录ip
6、LoginController调用UserService#loginSuccess()方法,进行登录成功的业务处理:
首先调用UserDao#updateLoginInfo()为用户添加5个积分,然后创建一个LoginLog对象,并利用LoginLogDao将其插入到数据库中
7、重定向到欢迎页面main.jsp,欢迎页面产生响应返回给用户

环境准备:

MySQL4.x不支持事务,所以需要MySQL5.x及以上
spring的声明式事务是依赖于底层数据库支持的

创建数据库表:

启动mysql,mysql -uroot -p1234 --port 3306
创建数据库

DROP DATABASE IF EXISTS sampledb;
CREATE DATABASE sampledb DEFAULT CHARACTER SET utf8;
USE sampledb;

创建数据表

##创建用户表
CREATE TABLE t_user(
	user_id int auto_increment primary key,
	user_name varchar(30),
	credits int,
	password varchar(32),
	last_visit datetime,
	last_ip varchar(23)
)ENGINE=InnoDB;
##创建用户登录日志表
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');
COMMIT;

也可以通过source命令运行脚本:

source D:\sampledb.sql

表结构
在这里插入图片描述
数据
在这里插入图片描述

建立工程:

我们为了方便,使用maven来构建web项目,具体方式查看:
IntelliJ IDEA创建maven web项目(IDEA新手适用)

使用的ide为intellij IDEA,建议将文件格式改为UTF-8来解决国际化问题,否则idea将使用默认的GBK编码格式
file-settings-editor-file encodings-将编码格式改为UTF-8
在这里插入图片描述

创建目录结构

在这里插入图片描述
说明:
在这里插入图片描述

spring的依赖

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.baobaotao</groupId>
  <artifactId>maven-web</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>maven-web Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <!--spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.13</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>

    <!--日志-->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>

    <!--数据库连接-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.44</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.1.1</version>
    </dependency>


    <!--测试框架-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.0.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
    
    <!--web-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>maven-web</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

类包规划
类包以分层的方式进行组织,共分为4个包,分别是dao、domain、service、web
领域对象从严格意义上属于业务层,但是由于领域对象可能同时被持久层和展现层共享,所以一般将其单独划分到一个包。

在这里插入图片描述

领域对象

领域对象也叫实体类,一般来说,领域对象属于业务层,但是他贯穿展现层、业务层、持久层,并最终被持久化到数据库中。
持久层从数据库表中加载数据并实例化领域对象,或者将领域对象持久化到数据表中。
论坛登录模块有2个领域对象:User和LoginLog,分别对应t_user和t_login_log数据表。

User.java

package com.baobaotao.domain;

import java.io.Serializable;
import java.util.Date;

//领域对象一般要实现Serializable接口,以便可以序列化
public class User implements Serializable {
    private int userId;
    private String userName;
    private String password;
    private int credits;
    private String lastIp;
    private Date lastVisit;
    //getter setter ...
}

LoginLog.java

package com.baobaotao.domain;

import java.io.Serializable;
import java.util.Date;

//领域对象一般要实现Serializable接口,以便可以序列化
public class LoginLog implements Serializable {
    private int loginLogId;
    private int userId;
    private String ip;
    private Date loginDate;
    //getter setter ...
}

数据访问层Dao

首先我们来定义访问User的dao,UserDao,他有3个方法:

getMatchCount();根据用户名密码获取匹配用户数,等于1表示用户名和密码正确,等于0表示用户名密码错误
这是最简单的用户身份认证方法,在实际应用中需要采用诸如密码加密等安全策略

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

updateLoginInfo();更新用户积分、最后登录ip和最后登录时间

下面通过springJDBC技术实现这个dao

spring2.5之后可以使用注解方式定义Bean,相对于XML配置方式,注解配置明显简单方便。

UserDao.java

package com.baobaotao.dao;

import com.baobaotao.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;

//通过spring注解定义一个dao
@Repository
public class UserDao{
    //自动注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public int getMatchCount(String userName,String password){
        String sqlStr="SELECT COUNT(*) FROM t_user WHERE user_name=? and password=? ";
        return jdbcTemplate.queryForInt(sqlStr,new Object[]{userName,password});

    }

    public User findUserByUserName(String userName){
        //根据用户名查询用户的sql语句
        String sqlStr="select user_id,user_name,credits from t_user where user_name=? ";
        User user=new User();
        jdbcTemplate.query(sqlStr, new Object[]{userName}, new RowCallbackHandler() {
            //匿名类方式实现的回调函数
            @Override
            public void processRow(ResultSet rs) throws SQLException {
                user.setUserId(rs.getInt("user_id"));
                user.setUserName(userName);
                user.setCredits(rs.getInt("credits"));
            }
        });
        return user;
    }


    public void updateLoginInfo(User user){
        String sqlStr="update t_user set last_visit=?,last_ip=?,credits=? where user_id=?";
        jdbcTemplate.update(sqlStr,new Object[]{user.getLastVisit(),user.getLastIp(),user.getCredits(),user.getUserId()});

    }
}

LoginLogDao负责记录用户登录日志,它仅有一个insertLoginLog()接口方法
LoginLogDao.java

package com.baobaotao.dao;

import com.baobaotao.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;

    public void insertLoginLog(LoginLog loginLog){
        String sqlStr="insert into t_login_log(user_id,ip,login_datetime)values(?,?,?)";
        Object[] args=new Object[]{loginLog.getUserId(),loginLog.getIp(),loginLog.getLoginDate()};
        jdbcTemplate.update(sqlStr,args);
    }
}

编写applicationContext.xml配置文件

在src目录添加applicationContext.xml文件
我们使用spring的<context:component-scan>扫描指定类包下的所有类,这样在类中定义的spring注解(@Repository,@Autowired)才能产生作用。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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:annotation-config/>
    <!--扫描类包,将标注spring注解的类自动转化为Bean,同时完成Bean的注入-->
    <context:component-scan base-package="com.baobaotao.dao"/>
  

    <!-- 配置Spring默认的连接池 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/sampledb"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>


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

</beans>

业务层

在论坛登录实例中,业务层只有一个业务类UserService,它负责将持久层UserDao和LoginLogDao组织起来完成用户密码认证,登录日志记录。

UserService.java

@Service
public class UserService{
	@Autowired
	private UserDao userDao;
	@Autowired
	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);
	}
	
	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);
	}
}

注意:
一般不会直接在数据库中以明文的方式保存用户的密码,因为这样容易造成密码的泄密问题,所以需将密码加密后以密文保存
一种更有效的办法是保存密码的MD5摘要
由于不能通过密码摘要反推出原来的密码,内部人员即使可以查看用户信息表,也无法知道用户的密码,所以摘要存储方式已经成为通用方式。
此外为了防止黑客使用工具进行密码暴力破解,大多数web使用了图片验证码功能,每次登陆都不相同,这样工具暴力破解无用武之地了。

在spring中装配service

事务管理的代码虽然不用出现在程序代码中,但是我们必须以某种方式告诉spring哪些业务类需要工作在事务环境中,以及事务的规则,以便spring自动根据这些信息为业务类添加事务管理功能。

修改applicationContext.xml文件:
扫描service类包,应用spring的注解配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">


    <context:annotation-config/>
    <!--扫描类包,将标注spring注解的类自动转化为Bean,同时完成Bean的注入-->
    <context:component-scan base-package="com.baobaotao.dao"/>
    <!--扫描service类包,应用spring的注解配置-->
    <context:component-scan base-package="com.baobaotao.service"/>

    <!-- 配置Spring默认的连接池 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/sampledb"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>


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

    <!--配置事务管理器-->
    <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.baobaotao.service..*(..))"/>
        <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>
</beans>

单元测试

添加一个test包用来存放测试代码

在这里插入图片描述
创建TestUserService类测试UserService的方法
TestUserService.java

package com.baobaotao.test;

import com.baobaotao.domain.User;
import com.baobaotao.service.UserService;
import org.junit.Assert;
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.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)//基于JUnit4的spring测试框架
@ContextConfiguration(locations={"/applicationContext.xml"})//启动spring容器
public class TestUserService{
    @Autowired
    private UserService userService;

    @Test//标注测试方法
    public void hasMatchUser(){
        boolean b1=userService.hasMatchUser("admin","123456");
        boolean b2=userService.hasMatchUser("admin","1111");
        Assert.assertTrue(b1);
        Assert.assertTrue(!b2);
    }

    @Test//标注测试方法
    public void findUserByUserName(){
        User user=userService.findUserByUserName("admin");
        Assert.assertEquals(user.getUserName(),"admin");
    }
}

点击小图标运行测试方法
在这里插入图片描述

展现层

配置springmvc框架
首先需要对web.xml文件进行配置,以便web容器启动时能够自动启动spring容器

web.xml
从类路径下加载spring配置文件,classpath关键字特指类路径下加载

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--1.从类路径下加载spring配置文件,classpath关键字特指类路径下加载-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      classpath:applicationContext.xml
    </param-value>
  </context-param>


  <!--2.负责启动spring容器的监听器,他会引用1的上下文参数获取spring配置文件地址-->
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>


</web-app>

首先通过web容器上下文参数指定spring配置文件地址,多个配置文件使用逗号或者空格分隔
指定spring提供的ContextLoaderListener的web容器监听器,他会在web启动自动运行,加载spring配置文件,并且启动spring容器。

注意:需要添加log4j.properties日志配置,以便日志引擎自动生效。
在这里插入图片描述

log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=info, stdout

配置SpringMVC框架

接下来,我们需要配置springmvc,他通过一个Servlet截获url请求,然后再进行相关处理
web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--1.从类路径下加载spring配置文件,classpath关键字特指类路径下加载-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      classpath:applicationContext.xml
    </param-value>
  </context-param>

  <!--2.负责启动spring容器的监听器,他会引用1的上下文参数获取spring配置文件地址-->
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>

  <!--1.springmvc的主控servlet-->
  <servlet>
    <servlet-name>baobaotao</servlet-name>
    <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
  </servlet>
  <!--2.springmvc处理的url-->
  <servlet-mapping>
    <servlet-name>baobaotao</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
</web-app>

springmvc也拥有一个spring配置文件,此处定义的Servlet有一个契约:servlet名-servlet.xml。

这里servlet名是baobaotao,所以必须提供一个baobaotao-servlet.xml的springmvc配置文件,springmvc的servlet会自动将baobaotao-servlet.xml和spring其他配置文件(baobaotao-dao.xml,baobaotao-service.xml)进行拼装。

在1声明了一个servletspringmvc也拥有一个spring配置文件,此处定义的Servlet有一个契约:servlet名-servlet.xml。
这里servlet名是baobaotao,所以必须提供一个baobaotao-servlet.xml的springmvc配置文件,springmvc的servlet会自动将baobaotao-servlet.xml和spring其他配置文件(baobaotao-dao.xml,baobaotao-service.xml)进行拼装。

在2对这个servlet的url路径映射定义,所有以.html为后缀的url都能被baobaotao servlet拦截,然后由springmvc框架处理。
使用.html后缀,用户不能通过url直接知道我们采用了何种服务端技术,另外.html是静态网页后缀,可以骗过搜索引擎,增加被收录的概率。
对于真正的无需任何动态处理的静态网页则可以使用.htm后缀区分,避免被框架截获。

请求被springmvc截获后,首先根据请求的url查找目标的处理控制器,并将请求参数封装到一个“命令”对象一起给控制器处理,控制器调用spring容器中的业务Bean完成业务处理工作并返回结果视图。

处理登录请求

pojo控制器
首先需要编写LoginController,他负责处理登录请求,完成登录业务,并根据登录成功与否转向欢迎页面或失败页面。
添加一个pojo包用来存放LoginCommand
LoginCommand.java

package com.baobaotao.pojo;

//登录请求pojo
public class LoginCommand{
    private String userName;
    private String password;
    //...

    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;
    }
}

LoginController.java

package com.baobaotao.web;

import com.baobaotao.domain.User;
import com.baobaotao.pojo.LoginCommand;
import com.baobaotao.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;

//1.标注成为一个springmvc的controller
@Controller
public class LoginController{
    @Autowired
    private UserService userService;

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

    //3.负责处理/loginCheck.html请求
    @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.getRemoteAddr());
            user.setLastVisit(new Date());
            userService.loginSuccess(user);
            request.getSession().setAttribute("user",user);
            return new ModelAndView("main");
        }
    }
}

1.springmvc的@Controller注解可以将任何一个pojo类标注为springmvc的控制器,处理http请求。
当然了,标注了@Controller的类首先是一个Bean,所以可以用@Autowired进行Bean注入。

2.一个控制器可以拥有多个对应不同http请求路径的处理方法,通过@RequestMapping指定方法如果映射请求路径
请求参数会根据参数名称匹配,绑定到loginCommand入参中。

3.请求响应方法可以返回一个ModelAndView,或直接返回一个字符串,springmvc会解析并转向目标响应页面。

配置springmvc

和web.xml在同一个目录
在这里插入图片描述
我们需要在baobaotao-servlet.xml中声明该控制器,扫描web路径,指定springmvc的视图解析器。
springmvc配置文件

baobaotao-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">

    <!--1.扫描web包,应用spring的注解-->
    <context:component-scan base-package="com.baobaotao.web"/>

    <!--2.配置视图解析器,将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>

springmvc为视图名到具体视图映射提供了许多方法,这里我们使用InternalResourceViewResolver,他通过为视图逻辑名添加前后缀的方法进行解析。

如果视图逻辑名为“login”将解析为/WEB-INF/jsp/login.jsp;名为“main”的视图解析为/WEB-INF/jsp/main.jsp。

jsp视图页面

登录模块一共包括2个jsp页面,分别是登录页面login.jsp和欢迎页面main.jsp。
需要用到jstl的jar包

	<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>

登录页面login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page isELIgnored="false" %>
<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"/>">
        用户名:<input type="text" name="userName" />
        <br/>
        密码:<input type="password" name="password" />
        <br/>
        <input type="submit" value="登录" />
        <input type="reset" value="重置" />
    </form>
</body>
</html>

login.jsp页面作为登录页面,也作为登录失败后的响应页面。

使用jstl标签对登录错误返回信息进行处理,jstl标签中应用了error变量,这个变量是LoginController中返回的ModelAndView(“login”,“error”,“用户名或密码错误。”)对象声明的error参数

login.jsp登录表单提交到/loginCheck.html,jstl标签会在url前面自动加上应用程序部署根目录,通过<c:url/>很好解决了开发和应用部署目录不一致问题。
由于login.jsp页面防止在WEB-INF/jsp目录下,无法直接通过url调用,所以他由LoginController的loginPage进行转发。

欢迎页面main.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=IOS-8859-1">
    <title>宝宝淘论坛</title>
</head>
<body>
    ${user.userName},欢迎您进入宝宝淘论坛,您当前的积分为${user.credits};
</body>
</html>

欢迎页面很简单,使用jstl标签显示一条欢迎信息,访问Session域中的user对象,显示用户名和积分信息。

运行web应用

启动tomcat,在浏览器输入:http://localhost:8080/index.html
在这里插入图片描述
用户名密码错误
在这里插入图片描述
用户名密码正确
在这里插入图片描述
每一次刷新页面,积分会加5分

总结:

我们使用了Spring MVC、Spring JDBC以及Spring声明式事务等技术实现了一个常见的论坛登录模块,让大家对如何使用Spring框架构建Web应用有了切身体会,同时还了解开发一个简单Web应用所需经理的开发过程。

当然实际开发中的过程的复杂性会更高,但是上所述步骤往往都是必需的,后续的功能开发也仅是在此基础上添砖加瓦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值