SSM框架

致虚极,守静笃

1. Spring概述

  1. Spring是一种轻量级开源框架,通常服务器端采用三层体系架构,分别为表现层(web)、业务逻辑层(service)、持久层(dao)

  2. 一般开发的三层架构为:数据访问层(DAL Data Access Layer)、业务逻辑层(BLL Business Logic Layer)、表现层(UI User Interface)、实体类库<不属于上面任何一层>(Model)

  3. 模块

    图片

  4. Core Container(核心容器)

    • Beans模块:提供了BeanFactory工厂
    • Core核心模块:包括Ioc和DI
    • Context上下文模块:建立在Beans和Core模块基础之上,访问定义和配置的任何对象的媒介,ApplicationContext接口是上下文的焦点
    • Context-support模块:提供了第三方嵌入Spring的集成支持,比如缓存,邮件服务,任务调度、模板引擎
    • SpEl模块:Spring3.0新增的模块,提供了Spring Expression Language支持
  5. Data Access/Integration

    • JDBC模块:提供JDBC抽象层,减少数据库操作
    • ORM模块:对流行的对象映射API,包括JPA、JDO和Hibernate提供了集成层支持
    • OXM模块:提供了一个支持对象/XML映射的抽象层实现,如JAXB、Castor、XMLBans、JiBX、XStream
    • JMS模块:Java消息传递服务
    • Transaction模块:对特殊接口实现和所有实体类声明式的事务管理
  6. Web

    • WebSocket模块:spring4.0新增,提供WebSockte以及ScokJS和对STOMP的支持

    • Servlet模块:也称spring-mvc模块

    • Web模块:基本的web开发集成特性

    • Portlet模块:提供了在Portlet环境中使用MVC实现

  7. 其他模块

    • AOP模块:提供了面向切面编程
    • Aspects模块:AspectJ的集成功能
    • Instrumentation模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用
    • Messaging模块:Spring4.0新增,对消息传递体系结构和协议的支持
    • Test 模块:对单元测试和集成测试,使用 JUnit 或 TestNG 框架的测试
  8. Spring框架包

  9. 使用的设计模式

    • 工厂设计模式(IOC容器)

    • 单例模式

      xml(默认为单例):

      1
      <bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>

      注解:

      @Scope(value = “singleton”)

    • 原型模式

      xml:

      1
      <bean id="userService" class="top.snailclimb.UserService" scope="prototype"/>

      注解:

      @Scope(value = “prototype”)

    • 代理设计模式(AOP\AspectJ)

    • 模板方法

      Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类

    • 观察者模式

      Spring 事件驱动模型

    • 适配者模式

      Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

    • 装饰者模式

      根据客户的需求能够动态切换不同的数据源

  10. Spring Boot

2. Spring IOC容器(思想:控制反转,Inversion of Control)

  1. BeanFactory

    这种加载方式开发并不多用,BeanFactory 接口有多个实现类,最常见的是 org.springframework.beans.factory.xml.XmlBeanFactory,它是根据 XML 配置文件中的定义装配 Bean 的。

1
BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D://applicationContext.xml"));
  1. ApplicationContext

    ApplicationContext 是 BeanFactory 的子接口,也被称为应用上下文。该接口的全路径为 org.springframework.context.ApplicationContext,它不仅提供了 BeanFactory 的所有功能,还添加了对 i18n(国际化)、资源访问、事件传播等方面的良好支持

  • ClassPathXmlApplicationContext

    该类从类路径 ClassPath 中寻找指定的 XML 配置文件

1
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
  • FileSystemXmlApplicationContext

    灵活性不强,不推荐使用,从硬盘的绝对路径下加载配置文件,

1
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);
  • XmlWebApplicationContext

    从Web系统中的XML文件载入上下文定义信息

  1. 配置文件

    Web 服务器实例化 ApplicationContext 容器通常使用基于 ContextLoaderListener 实现的方式,它只需要在 web.xml 中添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--指定Spring配置文件的位置,有多个配置文件时,以逗号分隔-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!--spring将加载spring目录下的applicationContext.xml文件-->
<param-value>
classpath:spring/applicationContext.xml
</param-value>
</context-param>
<!--指定以ContextLoaderListener方式启动Spring容器,防止创建多个applicationContext取值-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
  1. 区别

    • BeanFactory 和 ApplicationContext 都是通过 XML 配置文件加载 Bean 的

    • 如果 Bean 的某一个属性没有注入,则使用 BeanFacotry 加载后,在第一次调用 getBean() 方法时会抛出异常,而 ApplicationContext 则在初始化时自检,这样有利于检查所依赖的属性是否注入。

  2. 备注

    实现IOC思想需要DI做支持

3. Spring DI(方法:Dependency Injection,依赖注入)

  1. 依赖注入方式
    1. 基于XML装配
  • Setter注入(值类型用value注入 引用类型用ref注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--2.使用设值注入方式装配User实例 -->
<bean id="user2" class="com.itheima.assemble.User">
<property name="username" value="张三"></property>
<property name="password" value="654321"></property>
<property name="user" ref="user1"></property>
<!--复杂类型注入-->
<!-- 注入list集合 -->
<property name="list">
<list>
<value>"setlistvalue1"</value>
<value>"setlistvalue2"</value>
<ref bean="user1"></ref>
</list>
</property>

<!--1.array数组注入-->
<property name="array">
<array>
<value>value1</value>
<value>value2</value>
<ref bean="user1"></ref>
</array>
</property>
<!--3.map集合的注入-->
<property name="map">
<map>
<entry key="map1" value="map1"></entry>
<entry key="map2" value="map2"></entry>
<entry key-ref="user1" value-ref="user1"></entry>
</map>
</property>
<!-- 4.properties的注入-->
<property name="props">
<props>
<prop key="driverClass">com.jdbc.mysql.Driver</prop>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
</beans>
  • 构造方法注入(值类型用value注入 引用类型用ref注入
1
2
3
4
5
6
7
8
9
10
11
12
<!--1.使用构造注入方式装配User实例 -->
<bean id="user1" class="com.itheima.assemble.User">
<constructor-arg index="0" value="tom" />
<constructor-arg index="1" value="123456" />
<constructor-arg index="2">
<list>
<value>"constructorvalue1"</value>
<value>"constructorvalue2"</value>
</list>
</constructor-arg>
<constructor-arg index="3" ref="student" />
</bean>
  • 函数注入(实际上set注入,spring特有,为了简化写法
1
2
xmlns:p="http://www.springframework.org/schema/p"
<bean name="run2" class="cn.itcats.thread.Run" p:name="haha" p:age="20" p:hello-ref="hello"></bean>
  • spel注入
1
2
3
4
5
<!--SpEL特性:(1)、使用Bean的ID来引用Bean;(2)、调用方法和访问对象的属性;(3)、对值进行算术、关系和逻辑运算;(4)、正则表达式匹配;(5)、集合操作-->
<bean name="runSpel" class="cn.itcats.thread.Run">
<!-- 取bean标签中name为"user"中property为"name"中的value值 --!>
<property name="name" value="#{user.name}"></property>
</bean>
  • Spring配置别名
1
2
<!--设置别名:在获取Bean的时候可以使用别名获取-->
<alias name="userT" alias="userNew"/>
  1. 基于注解装配

    1
    2
    3
    <!--使用 context 命名空间 ,通知Spring扫描指定包下所有Bean类,进行注解解析-->   
    <context:component-scan base-package="com.itheima.annotation" />

    注解名称 说明
    @Component 此注解尽量少用,可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可
    @Repository 用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同
    @Service 通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同
    @Controller 通常作用在控制层(如 Struts2 的 Action),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同
    @Autowired 用于对 Bean 的属性变量、属性的 Set 方法及构造函数进行标注,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配
    @Resource 其作用与 Autowired 一样。其区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配name :按实例名称进行装配,type :按 Bean 类型进行装配
    @Qualifier 与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定
    @RunWith(SpringJUnit4ClassRunner.class) 创建Junit容器
    @ContextConfiguration(“classpath:.xml”) 指定容器的配置文件
    • 注意

      • @Value(“123”)值注入如果没有Set方法则通过反射field赋值,有则通过set赋值

      • @AutoWired和@Resource的区别?

        @AutoWired默认以类型进行查找,@Resource默认以名称进行查找

        @AutoWired(required=false) + @Qualifier(“user”) == @Resource(name=”user”)

        其中@Resource注解是jdk1.6后才有的

  2. 自动装配

    autowire名称 说明
    byName 根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。
    byType 根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。
    constructor 根据构造方法的参数的数据类型,进行 byType 模式的自动装配。
    autodetect 如果发现默认的构造方法,则用 constructor 模式,否则用 byType 模式。
    no 默认情况下,不使用自动装配,Bean 依赖必须通过 ref 元素定义。
    1
    2
    3
    4
    5
    6
    7
       <!-- 使用bean元素的autowire属性完成自动装配 -->
    <bean id="userDao"
    class="com.itheima.annotation.UserDaoImpl" />
    <bean id="userService"
    class="com.itheima.annotation.UserServiceImpl" autowire="byName" />
    <bean id="userController"
    class="com.itheima.annotation.UserController" autowire="byName"/>

4. Bean

  1. 实例化Bean:
  • 构造方法
1
<bean id="bean1" class="com.itheima.instance.constructor.Bean1" />
  • 静态工厂实例化
1
2
3
<bean id="bean2" 
class="com.itheima.instance.static_factory.MyBean2Factory"
factory-method="createBean" />
  • 实例工厂实例化
1
2
3
4
5
6
7
  <!-- 配置工厂 -->
<bean id="myBean3Factory"
class="com.itheima.instance.factory.MyBean3Factory" />
<!-- 使用factory-bean属性指向配置的实例工厂,
使用factory-method属性确定使用工厂中的哪个方法-->
<bean id="bean3" factory-bean="myBean3Factory"
factory-method="createBean" />
  1. bean元素的常用属性
属性名称 描述
id 是一个 Bean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成,没有id看name,name也没有看class
name Spring 容器同样可以通过此属性对容器中的 Bean 进行配置和管理,name 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开
class 该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,使用类的全限定名
scope 用于设定 Bean 实例的作用域,其属性值有 singleton(单例)、prototype(原型)、request、session 和 global Session。其默认值是 singleton
constructor-arg 元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型
property 元素的子元素,用于调用 Bean 实例中的 Set 方法完成属性赋值,从而完成依赖注入。该元素的 name 属性指定 Bean 实例中的相应属性名
ref 等元素的子元索,该元素中的 bean 属性用于指定对 Bean 工厂中某个 Bean 实例的引用
value 等元素的子元素,用于直接指定一个常量值
list 用于封装 List 或数组类型的依赖注入
set 用于封装 Set 类型属性的依赖注入
map 用于封装 Map 类型属性的依赖注入
entry 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值
  1. bean中的scope(作用域)
作用域名称 说明
singleton 单例模式,bean的默认值,使用 singleton 定义的 Bean 在 Spring 容器中只有一个实例,singleton作用域是Spring中的缺省作用域
prototype 原型模式,每次通过 Spring 容器获取 prototype 定义的 Bean 时,容器都将创建一个新的 Bean 实例
request 在一次 HTTP 请求中,容器会返回该 Bean 的同一个实例。而对不同的 HTTP 请求,会返回不同的实例,该作用域仅在当前 HTTP Request 内有效,Web环境下,对象与request生命周期一致
session Web环境下,对象与session生命周期一致,在一次 HTTP Session 中,容器会返回该 Bean 的同一个实例,该作用域仅在当前 HTTP Session 内有效
global Session 在一个全局的 HTTP Session 中,容器会返回该 Bean 的同一个实例。该作用域仅在使用 portlet context 时有效
application 为每个ServletContext对象创建一个实例,仅在使用portlet上下文时有效
websocket 为每个webSocket对象创建一个实例,仅在Web相关的ApplicationContext中生效

**注意 **

与struts整合时候,务必要用prototype多例,因为struts2在每次请求都会创建一个新的Action,若为单例,在多请求情况下,每个请求找找spring拿的都是同一个action。

  1. singleton 作用域下bean的生命周期

(1)配置一个方法作为生命周期初始化方法,spring会在对象创建之后立刻调用 init-method

(2)配置一个方法作为生命周期的销毁方法,spring容器在关闭并销毁所有容器中的对象之前调用destory-method

1
2
3
4
5
6
<bean init-method="init"  destory-method="destory"></bean>        <!-- 对应注解为@PostConstruct -->
<bean name=“hello” class=“完整类名”></bean> <!-- 对应注解为@PreDestory -->
分模块配置
<beans>
<import resource = “spring配置文件的全路径名” />
</beans>

5. AOP(Aspect Oriented Programming)

  1. 目前最流行的 AOP 框架有两个,分别为 Spring AOP 和 AspectJ。
  2. AOP专业术语
名称 说明
Joinpoint(连接点) 指那些被拦截到的点,在 Spring 中,可以被动态代理拦截目标类的方法。
Pointcut(切入点) 指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。
Advice(通知) 指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容。
Target(目标) 指代理的目标对象。
Weaving(织入) 指把增强代码应用到目标上,生成代理对象的过程,将通知应用到连接点形成切入点的过程。
Proxy(代理) 指生成的代理对象,将通知织入到目标对象之后形成的代理对象。
Aspect(切面) 切入点和通知的结合。
  1. Spring AOP
  • JDK动态代理
  • 栗子

(1)接口UserDao

1
2
3
4
5
package com.itheima.jdk;
interface UserDao {
public void addUser();
public void deleteUser();
}

(2) 接口实现类UserDaoImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.itheima.jdk;

import org.springframework.stereotype.Repository;

// 目标类
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
// int i = 10/0;
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}

(3) 切面类MyAspect

1
2
3
4
5
6
7
8
9
10
11
package com.itheima.jdk;
//切面类:可以存在多个通知Advice(即增强的方法)
public class MyAspect {
public void check_Permissions(){
System.out.println("模拟检查权限...");
}
public void log(){
System.out.println("模拟记录日志...");
}
}

(4) 代理类JdkProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.itheima.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* JDK代理类
*/
public class JdkProxy implements InvocationHandler{
//声明目标类接口
private UserDao userDao;
//创建代理方法
public Object createProxy(UserDao userDao) {
this.userDao = userDao;
//1.类加载器
ClassLoader classLoader = JdkProxy.class.getClassLoader();
//2.被代理对象实现的接口
Class[] clazz = userDao.getClass().getInterfaces();
//使用代理类,进行增强,返回代理后的对象
return Proxy.newProxyInstance(classLoader,clazz,this);
}
/*
* 所有动态代理类的方法调用,都会交由invoke()方法去处理
* proxy 被代理后的对象
* method 将要被执行的方法信息(反射)
* args 执行方法时需要的参数
*/
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//声明切面
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check_Permissions();
//在目标类上调用方法,并传入参数
Object object = method.invoke(userDao,objects);
//后增强
myAspect.log();
return object;
}


}

(5) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.itheima.jdk;
public class JdkTest{
public static void main(String[] args) {
// 创建代理对象
JdkProxy jdkProxy = new JdkProxy();
// 创建目标对象
UserDao userDao= new UserDaoImpl();
// 从代理对象中获取增强后的目标对象
UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
// 执行方法
userDao1.addUser();
userDao1.deleteUser();
}
}

  • CGLIB动态代理(没有实现接口的类)

(1) 目标类UserDao

1
2
3
4
5
6
7
8
9
10
11
package com.itheima.cglib;
//目标类
public class UserDao {
public void addUser() {
System.out.println("添加用户");
}
public void deleteUser() {
System.out.println("删除用户");
}
}

(2) 切面类MyAspect

1
2
3
4
5
6
7
8
9
10
11
package com.itheima.jdk;
//切面类:可以存在多个通知Advice(即增强的方法)
public class MyAspect {
public void check_Permissions(){
System.out.println("模拟检查权限...");
}
public void log(){
System.out.println("模拟记录日志...");
}
}

(3) 代理类CglibProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.itheima.cglib;
import java.lang.reflect.Method;

import com.itheima.jdk.MyAspect;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

// 代理类
public class CglibProxy implements MethodInterceptor{
// 代理方法
public Object createProxy(Object target) {
// 创建一个动态类对象
Enhancer enhancer = new Enhancer();
// 确定需要增强的类,设置其父类
enhancer.setSuperclass(target.getClass());
// 添加回调函数
enhancer.setCallback(this);
// 返回创建的代理类
return enhancer.create();
}
/**
* proxy CGlib根据指定父类生成的代理对象
* method 拦截的方法
* args 拦截方法的参数数组
* methodProxy 方法的代理对象,用于执行父类的方法
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
// 创建切面类对象
MyAspect myAspect = new MyAspect();
// 前增强
myAspect.check_Permissions();
// 目标方法执行
Object obj = methodProxy.invokeSuper(proxy, args);
// 后增强
myAspect.log();
return obj;
}
}

(4) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.itheima.cglib;
// 测试类
public class CglibTest {
public static void main(String[] args) {
// 创建代理对象
CglibProxy cglibProxy = new CglibProxy();
// 创建目标对象
UserDao userDao = new UserDao();
// 获取增强后的目标对象
UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
// 执行方法
userDao1.addUser();
userDao1.deleteUser();
}
}

  • 基于代理类的AOP实现
通知名字 英文 说明 使用场景
前置通知 Before Advice 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
环绕通知 Around Advice 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。 控制事务 权限控制
抛出异常后通知 After Throwing Advice 在方法抛出异常退出时执行的通知。 异常处理 控制事务
返回后通知【后置通知】 After Returning Advice 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。 记录日志(方法已经成功调用)
最终通知 After Advice 当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 记录日志(方法已经调用,但不一定成功)
  • 栗子

(1) 导入新包

  • aopalliance-1.0.jar

  • spring-aop-4.3.6.RELEASE.jar

(2) 接口UserDao

1
2
3
4
5
6
package com.itheima.factorybean;
public interface UserDao {
public void addUser();
public void deleteUser();
}

(3) 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itheima.factorybean;

import com.itheima.jdk.UserDao;
import org.springframework.stereotype.Repository;

// 目标类
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
// int i = 10/0;
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}

(4) 切面类MyAspect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.itheima.factorybean;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
// 切面类
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
check_Permissions();
// 执行目标方法
Object obj = mi.proceed();
log();
return obj;
}
public void check_Permissions(){
System.out.println("模拟检查权限...");
}
public void log(){
System.out.println("模拟记录日志...");
}
}

(5) 配置文件applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-4.3.xsd">
<!-- 1 目标类 -->
<bean id="userDao" class="com.itheima.factorybean.UserDaoImpl" />
<!-- 2 切面类 -->
<bean id="myAspect" class="com.itheima.factorybean.MyAspect" />
<!-- 3 使用Spring代理工厂定义一个名称为userDaoProxy的代理对象 -->
<bean id="userDaoProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 3.1 指定代理实现的接口-->
<property name="proxyInterfaces"
value="com.itheima.factorybean.UserDao" />
<!-- 3.2 指定目标对象 -->
<property name="target" ref="userDao" />
<!-- 3.3 指定切面,织入环绕通知 -->
<property name="interceptorNames" value="myAspect" />
<!-- 3.4 指定代理方式,true:使用cglib,false(默认):使用jdk动态代理 -->
<property name="proxyTargetClass" value="true" />
</bean>
</beans>

(6) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.itheima.factorybean;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.jdk.UserDao;
// 测试类
public class ProxyFactoryBeanTest {
public static void main(String args[]) {
String xmlPath = "com/itheima/factorybean/applicationContext.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
// 从Spring容器获得内容
UserDao userDao =
(UserDao) applicationContext.getBean("userDaoProxy");
// 执行方法
userDao.addUser();
userDao.deleteUser();
}
}

  1. AspectJ

基于Java语言的AOP框架

  • 基于XML的声明式

execution(* com.itheima.jdk.*.*(..)) 第一个星:返回值类型,第二个:类名,第三个:方法名,括号里面的点:任意参数

  • 栗子

(1) 导入新包

  • spring-aspects-4.3.6.RELEASE.jar
  • aspectjweaver-1.8.10.jar

(2) 切面类MyAspect

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.itheima.aspectj.xml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
*切面类,在此类中编写通知
*/
public class MyAspect {
// 前置通知
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知 :模拟执行权限检查...,");
System.out.print("目标类是:"+joinPoint.getTarget() );
System.out.println(",被织入增强处理的目标方法为:"
+joinPoint.getSignature().getName());
}
// 后置通知
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志...," );
System.out.println("被织入增强处理的目标方法为:"
+ joinPoint.getSignature().getName());
}
/**
* 环绕通知
* ProceedingJoinPoint 是JoinPoint子接口,表示可以执行目标方法
* 1.必须是Object类型的返回值
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须throws Throwable
*/
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
// 执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
// 结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
return obj;
}
// 异常通知
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知:" + "出错了" + e.getMessage());
}
// 最终通知
public void myAfter() {
System.out.println("最终通知:模拟方法结束后的释放资源...");
}
}

(3) 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 1 目标类 -->
<bean id="userDao" class="com.itheima.jdk.UserDaoImpl" />
<!-- 2 切面 -->
<bean id="myAspect" class="com.itheima.aspectj.xml.MyAspect" />
<!-- 3 aop编程 -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<!-- 3.1 配置切入点,通知最后增强哪些方法 -->
<aop:pointcut expression="execution(* com.itheima.jdk.*.*(..))"
id="myPointCut" />
<!-- 3.2 关联通知Advice和切入点pointCut -->
<!-- 3.2.1 前置通知 -->
<aop:before method="myBefore" pointcut-ref="myPointCut" />
<!-- 3.2.2 后置通知,在方法返回之后执行,就可以获得返回值
returning属性:用于设置后置通知的第二个参数的名称,类型是Object -->
<aop:after-returning method="myAfterReturning"
pointcut-ref="myPointCut" returning="returnVal" />
<!-- 3.2.3 环绕通知 -->
<aop:around method="myAround" pointcut-ref="myPointCut" />
<!-- 3.2.4 抛出通知:用于处理程序发生异常-->
<!-- * 注意:如果程序没有异常,将不会执行增强 -->
<!-- * throwing属性:用于设置通知第二个参数的名称,类型Throwable -->
<aop:after-throwing method="myAfterThrowing"
pointcut-ref="myPointCut" throwing="e" />
<!-- 3.2.5 最终通知:无论程序发生任何事情,都将执行 -->
<aop:after method="myAfter" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
</beans>

(4) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itheima.aspectj.xml;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.jdk.UserDao;
// 测试类
public class TestXmlAspectj {
public static void main(String args[]) {
String xmlPath =
"com/itheima/aspectj/xml/applicationContext.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
// 1 从spring容器获得内容
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
// 2 执行方法
userDao.addUser();
}
}

  • 基于注解的声明式

(1) 在基于xml的声明上,重新写一个切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.itheima.aspectj.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 切面类,在此类中编写通知
*/
@Aspect
@Component
public class MyAspect {
// 定义切入点表达式
@Pointcut("execution(* com.itheima.jdk.*.*(..))")
// 使用一个返回值为void、方法体为空的方法来命名切入点
private void myPointCut(){}
// 前置通知
@Before("myPointCut()")
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知 :模拟执行权限检查...,");
System.out.print("目标类是:"+joinPoint.getTarget() );
System.out.println(",被织入增强处理的目标方法为:"
+joinPoint.getSignature().getName());
}
// 后置通知
@AfterReturning(value="myPointCut()")
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志...," );
System.out.println("被织入增强处理的目标方法为:"
+ joinPoint.getSignature().getName());
}
// 环绕通知
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
// 执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
// 结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
return obj;
}
// 异常通知
@AfterThrowing(value="myPointCut()",throwing="e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知:" + "出错了" + e.getMessage());
}
// 最终通知
@After("myPointCut()")
public void myAfter() {
System.out.println("最终通知:模拟方法结束后的释放资源...");
}
}

(2) 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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:aop="http://www.springframework.org/schema/aop"
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.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 指定需要扫描的包,使注解生效 -->
<context:component-scan base-package="com.itheima.factorybean com.itheima.aspectj.annotation" />
<!-- 启动基于注解的声明式AspectJ支持 -->
<aop:aspectj-autoproxy />
</beans>

(3) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itheima.aspectj.annotation;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.jdk.UserDao;
// 测试类
public class TestAnnotationAspectj {
public static void main(String args[]) {
String xmlPath =
"com/itheima/aspectj/annotation/applicationContext.xml";
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
// 1 从spring容器获得内容
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
// 2 执行方法
userDao.addUser();
}
}

6. Spring 数据库开发

Spring JdbcTemplate解析,推荐使用MyBatis

  • 栗子

(1) 导入新包

  • mysql-connector-java-5.1.8.jar
  • spring-jdbc-4.3.6.RELEASE.jar
  • spring-tx-4.3.6.RELEASE.jar

(2) 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-4.3.xsd">
<!-- 1配置数据源 -->
<bean id="dataSource" class=
"org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<!--连接数据库的url -->
<property name="url" value="jdbc:mysql://localhost:3306/spring" />
<!--连接数据库的用户名 -->
<property name="username" value="root" />
<!--连接数据库的密码 -->
<property name="password" value="root" />
</bean>
<!-- 2配置JDBC模板 -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 默认必须使用数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>

<!--定义id为accountDao的Bean-->
<bean id="accountDao" class="com.itheima.jdbc.AccountDaoImpl">
<!-- 将jdbcTemplate注入到accountDao实例中 -->
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>

</beans>

(3) 实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.itheima.jdbc;
public class Account {
private Integer id; // 账户id
private String username; // 用户名
private Double balance; // 账户余额
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Double getBalance() {
return balance;
}
public void setBalance(Double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account [id=" + id + ", "
+ "username=" + username +
", balance=" + balance + "]";
}
}

(4) 数据访问类接口Dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.itheima.jdbc;

import java.util.List;

public interface AccountDao {
// 添加
public int addAccount(Account account);
// 更新
public int updateAccount(Account account);
// 删除
public int deleteAccount(int id);

// 通过id查询
public Account findAccountById(int id);
// 查询所有账户
public List<Account> findAllAccount();
}

(5) 数据访问类实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package com.itheima.jdbc;
import java.util.List;

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class AccountDaoImpl implements AccountDao {
// 声明JdbcTemplate属性及其setter方法
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// 添加账户

@Override
public int addAccount(Account account) {
// 定义SQL
String sql = "insert into tb_account(account_id,username,money) values(?,?,?);";
// 定义数组来存放SQL语句中的参数
Object[] obj = new Object[] {
account.getId(),
account.getUsername(),
account.getBalance()
};
// 执行添加操作,返回的是受SQL语句影响的记录条数
int num = this.jdbcTemplate.update(sql, obj);
return num;
}
// 更新账户
@Override
public int updateAccount(Account account) {
// 定义SQL
String sql = "update account set username=?,balance=? where id = ?";
// 定义数组来存放SQL语句中的参数
Object[] params = new Object[] {
account.getUsername(),
account.getBalance(),
account.getId()
};
// 执行添加操作,返回的是受SQL语句影响的记录条数
int num = this.jdbcTemplate.update(sql, params);
return num;
}
// 删除账户
@Override
public int deleteAccount(int id) {
// 定义SQL
String sql = "delete from account where id = ? ";
// 执行添加操作,返回的是受SQL语句影响的记录条数
int num = this.jdbcTemplate.update(sql, id);
return num;
}

// 通过id查询账户数据信息
@Override
public Account findAccountById(int id) {
//定义SQL语句
String sql = "select * from account where id = ?";
// 创建一个新的BeanPropertyRowMapper对象
RowMapper<Account> rowMapper =
new BeanPropertyRowMapper<Account>(Account.class);
// 将id绑定到SQL语句中,并通过RowMapper返回一个Object类型的单行记录
return this.jdbcTemplate.queryForObject(sql, rowMapper, id);
}
// 查询所有账户信息
@Override
public List<Account> findAllAccount() {
// 定义SQL语句
String sql = "select * from account";
// 创建一个新的BeanPropertyRowMapper对象
RowMapper<Account> rowMapper =
new BeanPropertyRowMapper<Account>(Account.class);
// 执行静态的SQL查询,并通过RowMapper返回结果
return this.jdbcTemplate.query(sql, rowMapper);
}

}

(6) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package com.itheima.jdbc;
import java.util.List;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class JdbcTemplateTest {
/**
* 使用execute()方法建表
*/
// public static void main(String[] args) {
// // 加载配置文件
// ApplicationContext applicationContext =
// new ClassPathXmlApplicationContext("applicationContext.xml");
// // 获取JdbcTemplate实例
// JdbcTemplate jdTemplate =
// (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
// // 使用execute()方法执行SQL语句,创建用户账户管理表account
// jdTemplate.execute("create table account(" +
// "id int primary key auto_increment," +
// "username varchar(50)," +
// "balance double)");
// System.out.println("账户表account创建成功!");
// }

@Test
public void mainTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取JdbcTemplate实例
JdbcTemplate jdTemplate =
(JdbcTemplate) applicationContext.getBean("jdbcTemplate");
// 使用execute()方法执行SQL语句,创建用户账户管理表account
jdTemplate.execute("create table account(" +
"id int primary key auto_increment," +
"username varchar(50)," +
"balance double)");
System.out.println("账户表account创建成功!");
}

@Test
public void addAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 创建Account对象,并向Account对象中添加数据
Account account = new Account();
account.setId(30);
account.setUsername("tom");
account.setBalance(1000.00);
// 执行addAccount()方法,并获取返回结果
int num = accountDao.addAccount(account);
if (num > 0) {
System.out.println("成功插入了" + num + "条数据!");
} else {
System.out.println("插入操作执行失败!");
}
}

@Test
public void updateAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 创建Account对象,并向Account对象中添加数据
Account account = new Account();
account.setId(1);
account.setUsername("tom");
account.setBalance(2000.00);
// 执行updateAccount()方法,并获取返回结果
int num = accountDao.updateAccount(account);
if (num > 0) {
System.out.println("成功修改了" + num + "条数据!");
} else {
System.out.println("修改操作执行失败!");
}
}

@Test
public void deleteAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 执行deleteAccount()方法,并获取返回结果
int num = accountDao.deleteAccount(1);
if (num > 0) {
System.out.println("成功删除了" + num + "条数据!");
} else {
System.out.println("删除操作执行失败!");
}
}

@Test
public void findAccountByIdTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 执行findAccountById()方法
Account account = accountDao.findAccountById(1);
System.out.println(account);
}

@Test
public void findAllAccountTest() {
// 加载配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao) applicationContext.getBean("accountDao");
// 执行findAllAccount()方法,获取Account对象的集合
List<Account> account = accountDao.findAllAccount();
// 循环输出集合中的对象
for (Account act : account) {
System.out.println(act);
}
}
}

7.Spring事务管理

  1. 事务管理核心接口
  • PlatformTransactionManager(接口是Spring提供的平台事务管理器)
方法 类型 说明
TransactionStatus getTransaction(TransactionDefinition definition) 普通 用于获取事务状态信息
void commit(TransactionStatus status) 普通 用于提交事务
void rollback(TransactionStatus status) 普通 用于回滚事务
  • TransactionDefinition(接口是事务定义(描述)的对象)
方法 类型 说明
String getName( ) 普通 获取事务对象名称
int getIsolationLevel( ) 普通 获取事务的隔离级别
int getPropagationBehavior( ) 普通 获取事务的传播行为
int getTimeout( ) 普通 获取事务的超时时间
boolean isReadOnly( ) 普通 获取事务是否可读
  • TransactionStatus(事务的状态)

是否有保存点

是否一个新的事务

事务是否已经提交

  1. 基于XML方式声明式事务
  • 栗子

(1) 导入新包

- aopalliance-1.0.jar
- aspectjweaver-1.8.10.jar
- spring-aop-4.3.6.RELEASE.jar
- spring-aspects-4.3.6.RELEASE.jar
- mysql-connector-java-5.1.8.jar
- spring-tx-4.3.6.RELEASE.jar

(2) 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 1.配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<!--连接数据库的url -->
<property name="url" value="jdbc:mysql://localhost/temp1" />
<!--连接数据库的用户名 -->
<property name="username" value="root" />
<!--连接数据库的密码 -->
<property name="password" value="root" />
</bean>
<!-- 2.配置JDBC模板 -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 默认必须使用数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!--3.定义id为accountDao的Bean -->
<bean id="accountDao" class="com.itheima.jdbc.AccountDaoImpl">
<!-- 将jdbcTemplate注入到AccountDao实例中 -->
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<!-- 4.事务管理器,依赖于数据源 -->
<bean id="transactionManager" class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 5.编写通知:对事务进行增强(通知),需要编写对切入点和具体执行事务细节 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- name:*表示任意方法名称 -->
<tx:method name="*" propagation="REQUIRED"
isolation="DEFAULT" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- 6.编写aop,让spring自动对目标生成代理,需要使用AspectJ的表达式 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution(* com.itheima.jdbc.*.*(..))"
id="txPointCut" />
<!-- 切面:将切入点与通知整合 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
</aop:config>
</beans>

(3) 在上一次的AccountDao接口加方法

1
public void transfer(String outUser,String inUser,Double money);

(4) 实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT, readOnly = false)
public void transfer(String outUser, String inUser, Double money) {
// 收款时,收款用户的余额=现有余额+所汇金额
this.jdbcTemplate.update("update account set balance = balance +? "
+ "where username = ?",money, inUser);
// 模拟系统运行时的突发性问题
int i = 1/0;
// 汇款时,汇款用户的余额=现有余额-所汇金额
this.jdbcTemplate.update("update account set balance = balance-? "
+ "where username = ?",money, outUser);
}

(5) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.itheima.jdbc;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
//测试类
public class TransactionTest {
@Test
public void xmlTest(){
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao)applicationContext.getBean("accountDao");
// 调用实例中的转账方法
accountDao.transfer("Jack", "Rose", 100.0);
// 输出提示信息
System.out.println("转账成功!");
}

@Test
public void annotationTest(){
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext-annotation.xml");
// 获取AccountDao实例
AccountDao accountDao =
(AccountDao)applicationContext.getBean("accountDao");
// 调用实例中的转账方法
accountDao.transfer("Jack", "Rose", 100.0);
// 输出提示信息
System.out.println("转账成功!");
}

}

  1. 基于注解方式声明式事务

(1) 在实现类增加注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.DEFAULT, readOnly = false)
public void transfer(String outUser, String inUser, Double money) {
// 收款时,收款用户的余额=现有余额+所汇金额
this.jdbcTemplate.update("update account set balance = balance +? "
+ "where username = ?",money, inUser);
// 模拟系统运行时的突发性问题
int i = 1/0;
// 汇款时,汇款用户的余额=现有余额-所汇金额
this.jdbcTemplate.update("update account set balance = balance-? "
+ "where username = ?",money, outUser);
}

(2) 修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 1.配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--数据库驱动 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<!--连接数据库的url -->
<property name="url" value="jdbc:mysql://localhost/temp1" />
<!--连接数据库的用户名 -->
<property name="username" value="root" />
<!--连接数据库的密码 -->
<property name="password" value="root" />
</bean>
<!-- 2.配置JDBC模板 -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 默认必须使用数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!--3.定义id为accountDao的Bean -->
<bean id="accountDao" class="com.itheima.jdbc.AccountDaoImpl">
<!-- 将jdbcTemplate注入到AccountDao实例中 -->
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<!-- 4.事务管理器,依赖于数据源 -->
<bean id="transactionManager" class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 5.注册事务管理器驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

(3) 测试

8. MyBatis

持久层框架

  1. 工作原理

image-20210630181734459

  • 栗子

(1) 导入新包

  • mybatis-3.4.2.jar
  • mysql-connector-java-5.1.40-bin.jar

(2) 配置日志信息log4j.properties

1
2
3
4
5
6
7
8
9
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.itheima=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

(3) 持久类entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.itheima.po;
/**
* 客户持久化类
*/
public class Customer {
private Integer id; // 主键id
private String username; // 客户名称
private String jobs; // 职业
private String phone; // 电话
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getJobs() {
return jobs;
}
public void setJobs(String jobs) {
this.jobs = jobs;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Customer [id=" + id + ", username=" + username +
", jobs=" + jobs + ", phone=" + phone + "]";
}
}

(4) 映射文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace表示命名空间 -->
<mapper namespace="com.itheima.mapper.CustomerMapper">
<!--根据客户编号获取客户信息 -->
<select id="findCustomerById" parameterType="Integer"
resultType="com.itheima.po.Customer">
select * from t_customer where id = #{id}
</select>

<!--根据客户名模糊查询客户信息列表-->
<select id="findCustomerByName" parameterType="String"
resultType="com.itheima.po.Customer">
<!-- select * from t_customer where username like '%${value}%' -->
select * from t_customer where username like concat('%',#{value},'%')
</select>

<!-- 添加客户信息 -->
<insert id="addCustomer" parameterType="com.itheima.po.Customer">
insert into t_customer(username,jobs,phone)
values(#{username},#{jobs},#{phone})
</insert>

<!-- 更新客户信息 -->
<update id="updateCustomer" parameterType="com.itheima.po.Customer">
update t_customer set
username=#{username},jobs=#{jobs},phone=#{phone}
where id=#{id}
</update>

<!-- 删除客户信息 -->
<delete id="deleteCustomer" parameterType="Integer">
delete from t_customer where id=#{id}
</delete>
</mapper>

(5) MyBatis配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--1.配置环境 ,默认的环境id为mysql-->
<environments default="mysql">
<!--1.2.配置id为mysql的数据库环境 -->
<environment id="mysql">
<!-- 使用JDBC的事务管理 -->
<transactionManager type="JDBC" />
<!--数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!--2.配置Mapper的位置 -->
<mappers>
<mapper resource="com/itheima/mapper/CustomerMapper.xml" />
</mappers>
</configuration>

(6) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package com.itheima.test;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import com.itheima.po.Customer;
/**
* 入门程序测试类
*/
public class MybatisTest {
/**
* 根据客户编号查询客户信息
*/
@Test
public void findCustomerByIdTest() throws Exception {
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream =
Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4、SqlSession执行映射文件中定义的SQL,并返回映射结果
Customer customer = sqlSession.selectOne("com.itheima.mapper"
+ ".CustomerMapper.findCustomerById", 1);
// 打印输出结果
System.out.println(customer.toString());
// 5、关闭SqlSession
sqlSession.close();
}

/**
* 根据用户名称来模糊查询用户信息列表
*/
@Test
public void findCustomerByNameTest() throws Exception{
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4、SqlSession执行映射文件中定义的SQL,并返回映射结果
List<Customer> customers = sqlSession.selectList("com.itheima.mapper"
+ ".CustomerMapper.findCustomerByName", "j");
for (Customer customer : customers) {
//打印输出结果集
System.out.println(customer);
}
// 5、关闭SqlSession
sqlSession.close();
}

/**
* 添加客户
*/
@Test
public void addCustomerTest() throws Exception{
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4、SqlSession执行添加操作
// 4.1创建Customer对象,并向对象中添加数据
Customer customer = new Customer();
customer.setUsername("rose");
customer.setJobs("student");
customer.setPhone("13333533092");
// 4.2执行SqlSession的插入方法,返回的是SQL语句影响的行数
int rows = sqlSession.insert("com.itheima.mapper"
+ ".CustomerMapper.addCustomer", customer);
// 4.3通过返回结果判断插入操作是否执行成功
if(rows > 0){
System.out.println("您成功插入了"+rows+"条数据!");
}else{
System.out.println("执行插入操作失败!!!");
}
// 4.4提交事务
sqlSession.commit();
// 5、关闭SqlSession
sqlSession.close();
}

/**
* 更新客户
*/
@Test
public void updateCustomerTest() throws Exception{
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4、SqlSession执行更新操作
// 4.1创建Customer对象,对对象中的数据进行模拟更新
Customer customer = new Customer();
customer.setId(4);
customer.setUsername("rose");
customer.setJobs("programmer");
customer.setPhone("13311111111");
// 4.2执行SqlSession的更新方法,返回的是SQL语句影响的行数
int rows = sqlSession.update("com.itheima.mapper"
+ ".CustomerMapper.updateCustomer", customer);
// 4.3通过返回结果判断更新操作是否执行成功
if(rows > 0){
System.out.println("您成功修改了"+rows+"条数据!");
}else{
System.out.println("执行修改操作失败!!!");
}
// 4.4提交事务
sqlSession.commit();
// 5、关闭SqlSession
sqlSession.close();
}

/**
* 删除客户
*/
@Test
public void deleteCustomerTest() throws Exception{
// 1、读取配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 2、根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
// 3、通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4、SqlSession执行删除操作
// 4.1执行SqlSession的删除方法,返回的是SQL语句影响的行数
int rows = sqlSession.delete("com.itheima.mapper"
+ ".CustomerMapper.deleteCustomer", 4);
// 4.2通过返回结果判断删除操作是否执行成功
if(rows > 0){
System.out.println("您成功删除了"+rows+"条数据!");
}else{
System.out.println("执行删除操作失败!!!");
}
// 4.3提交事务
sqlSession.commit();
// 5、关闭SqlSession
sqlSession.close();
}

}

附:MySQL语句

1
2
3
4
5
6
create table if not exists `t_customer`(
id int primary key AUTO_INCREMENT,
username VARCHAR(20),
jobs VARCHAR(20),
phone VARCHAR(20)
)AUTO_INCREMENT=0001 default charset=utf8;
  1. SqlSession

是MyBatis的关键对象,是执行持久化操作的独享,类似于JDBC中的Connection,线程不安全,使用完要确保finally关闭它

  • SqlSessionFactory源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.apache.ibatis.session;

import java.sql.Connection;

public interface SqlSessionFactory {

SqlSession openSession();//这个方法最经常用,用来创建SqlSession对象.

SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);

SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);

Configuration getConfiguration();

}
  1. MyBatis配置文件
  • 栗子

(1) log4j.properties【用于控制台输出】

1
2
3
4
5
6
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

(2) db.properties文件

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/temp1
jdbc.username=root
jdbc.password=root

(3) MyBatis配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties" />
<!-- 定义别名 -->
<typeAliases>
<!-- <typeAlias alias="user" type="com.itheima.po.User" /> -->
<!--只适合没有entity包注解-->
<package name="com.itheima.po" />
</typeAliases>

<!-- 配置自定义工厂 -->
<objectFactory type="com.itheima.factory.MyObjectFactory">
<property name="name" value="MyObjectFactory"/>
</objectFactory>
<!--常见配置-->
<!-- <settings>
<setting name="cacheEnabled" value="true" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyloading" value="true" />
<setting name="multipleResultSetsEnabled" value="true" />
<setting name="useColumnLabel" value="true" />
<setting name="useGeneratedKeys" value="false" />
<setting name="autoMappingBehavior" value="PARTIAL" />
<setting name="defa" value="PARTIAL" />

<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="30"/>
<setting name="defaultFetchSize" value="200"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>

</settings>-->

<!--注册一个类型处理器-->
<!-- <typeHandlers>
<typeHandler handler="com.itheima.po.Customer" />
</typeHandlers>-->
<!--注册一个包中所有的类型处理器-->
<!--<typeHandlers>
<typeHandler handler="com.itheima.po" />
</typeHandlers>-->
<!--1.配置环境 ,默认的环境id为mysql -->
<environments default="mysql">
<!--1.2.配置id为mysql的数据库环境 -->
<environment id="mysql">
<!-- 使用JDBC的事务管理 -->
<transactionManager type="JDBC" />
<!--数据库连接池 -->
<dataSource type="POOLED">
<!-- 数据库驱动 -->
<property name="driver" value="${jdbc.driver}" />
<!-- 连接数据库的url -->
<property name="url" value="${jdbc.url}" />
<!-- 连接数据库的用户名 -->
<property name="username" value="${jdbc.username}" />
<!-- 连接数据库的密码 -->
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>

<!--2.配置Mapper的位置 -->
<mappers>
<!--使用类路径引入-->
<mapper resource="com/itheima/mapper/CustomerMapper.xml" />
<mapper resource="com/itheima/mapper/UserMapper.xml" />
<!--使用本地路径引入-->
<!--<mapper url="file:\\\C:\Users\xxy\Desktop\SSM\源代码\ssmcode\chapter07\src\com\itheima\mapper\CustomerMapper.xml"-->
<!--使用接口类引入-->
<!--<mapper class="com.itheima.mapper.CustomerMapper.xml" />-->
<!--使用包名引入-->
<<!--package name="com.itheima.mapper" />-->
</mappers>
</configuration>

(4) 映射文件+动态SQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.StudentMapper">
<!-- <resultMap id="resultMap" type="student">
<id property="stu_id" column="stu_id" />
<result property="classid" column="class_id" />
<result property="stu_name" column="stu_name" />
<result property="st_sex" column="stu_sex" />
<result property="stu_telphone" column="stu_telphone" />
</resultMap>-->
<select id="findStudentByNameAndPhoneUseWhere"
parameterType="student"
resultType="student"
flushCache="false"
useCache="true"
timeout="20">
<bind name="pattern_stu_name" value="'%'+_parameter.getStu_name()+'%'" />
select * from t_student
<where>
<if test="stu_name != null and stu_name != ''">
and stu_name like concat('%',#{stu_name},'%')
</if>
<if test="stu_telphone != null and stu_telphone != ''">
and stu_telphone = #{stu_telphone}
</if>
</where>
</select>
<select id="findStudentByNameAndPhoneUseTrim"
parameterType="student"
resultType="student"
flushCache="false"
useCache="true"
timeout="10">
select * from t_student
<trim prefix="where" prefixOverrides="and">
<if test="stu_name !=null and stu_name !=''">
and stu_name like concat('%',#{stu_name},'%')
</if>
<if test="stu_telphone !=null and stu_telphone !=''">
and stu_telphone = #{stu_telphone}
</if>
</trim>
</select>
<select id="findStudentByNameAndClass"
parameterType="student"
resultType="student"
flushCache="false"
useCache="true"
timeout="10">
select * from t_student where 1=1
<choose>
<when test="stu_name !=null and stu_name !=''">
and stu_name like concat('%',#{stu_name},'%')
</when>
<when test="class_id !=null and class_id !=''">
and class_id = #{class_id}
</when>
<otherwise>
and stu_telphone is not null
</otherwise>
</choose>
</select>
<select id="findStudentByManyClasses"
parameterType="java.util.ArrayList"
resultType="student"
flushCache="false"
useCache="true"
timeout="10">
select * from t_student where class_id in
<foreach collection="array" item="id" index="index" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<insert id="addStudent"
parameterType="student"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys="false"
timeout="20">
insert into t_student values (#{stu_id},#{class_id},#{stu_name},#{stu_sex},#{stu_telphone})
</insert>
<update id="updateStudentByValue"
parameterType="student"
flushCache="true"
statementType="PREPARED"
timeout="20">
update t_student
<set>
<if test="stu_name != null and stu_name != ''">
stu_name = #{stu_name},
</if>
<if test="class_id != null and class_id != ''">
class_id = #{class_id},
</if>
<if test="stu_telphone != null and stu_telphone != ''">
stu_telphone = #{stu_telphone},
</if>
</set>
where stu_id = #{stu_id}
</update>
<delete id="deleteStudentByName"
parameterType="student"
flushCache="true"
statementType="PREPARED"
timeout="20">
<bind name="pattern_stu_name" value="'%'+_parameter.getStu_name()+'%'" />
delete from t_student
where
stu_name like #{pattern_stu_name}
</delete>
</mapper>

(5) MyBatis工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package edu.hhtc.jsj.utils;

import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* 工具类
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory = null;
// 初始化SqlSessionFactory对象
static {
try {
// 使用MyBatis提供的Resources类加载MyBatis的配置文件
Reader reader =
Resources.getResourceAsReader("mybatis-config.xml");
// 构建SqlSessionFactory工厂
sqlSessionFactory =
new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取SqlSession对象的静态方法
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}


(6) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import edu.hhtc.jsj.dao.StudentDao;
import edu.hhtc.jsj.dao.StudentDaoImpl;
import edu.hhtc.jsj.entity.Student;
import org.junit.Test;

import java.sql.SQLException;
import java.util.List;

public class MybatisTest {

@Test
public void findStudentByNameAndPhoneUseWhereTest() throws SQLException{
// 1、创建方法调用需要的参数,设置Student的成员值
Student stu=new Student();
//2、创建Dao实例
StudentDao studao=new StudentDaoImpl();
//3、调用studao实例的方法进行测试
//studao.xxxxx(stu);
stu.setStu_name("向");
stu.setStu_telphone("");
List<Student> students = studao.findStudentByNameAndPhoneUseWhere(stu);
for(Student student : students){
System.out.println(student.toString());
}
}


@Test
public void findStudentByNameAndPhoneUseTrimTest() throws SQLException{
// 1、创建方法调用需要的参数,设置Student的成员值
Student stu=new Student();
//2、创建Dao实例
StudentDao studao=new StudentDaoImpl();
//3、调用studao实例的方法进行测试
//studao.xxxxx(stu);
stu.setStu_name("");
stu.setStu_telphone("1234575");
List<Student> students = studao.findStudentByNameAndPhoneUseTrim(stu);
for(Student student : students){
System.out.println(student.toString());
}
}


@Test
public void findStudentByNameAndClassTest() throws SQLException{
// 1、创建方法调用需要的参数,设置Student的成员值
Student stu=new Student();
//2、创建Dao实例
StudentDao studao=new StudentDaoImpl();
//3、调用studao实例的方法进行测试
//studao.xxxxx(stu);
stu.setStu_name("");
stu.setClass_id("1506401");
List<Student> students = studao.findStudentByNameAndClass(stu);
for(Student student : students){
System.out.println(student.toString());
}
}


@Test
public void updateStudentByValueTest() throws SQLException{
// 1、创建方法调用需要的参数,设置Student的成员值
Student stu=new Student();
//2、创建Dao实例
StudentDao studao=new StudentDaoImpl();
//3、调用studao实例的方法进行测试
//studao.xxxxx(stu);
stu.setStu_id("1006401023");
stu.setStu_name("向小波");
stu.setStu_telphone("1234574");
int n = studao.updateStudentByValue(stu);
if(n > 0){
System.out.println("成功修改了"+n+"条数据!");
}else {
System.out.println("修改失败!");
}
}


@Test
public void findStudentByManyClassesTest() throws SQLException{
//2、创建Dao实例
StudentDao studao=new StudentDaoImpl();
//3、调用studao实例的方法进行测试
//studao.xxxxx(stu);
String[] classes = {"1506401","1706401"};
List<Student> students = studao.findStudentByManyClasses(classes);
for(Student student : students){
System.out.println(student.toString());
}
}


@Test
public void deleteStudentByNameTest() throws SQLException{
// 1、创建方法调用需要的参数,设置Student的成员值
Student stu=new Student();
//2、创建Dao实例
StudentDao studao=new StudentDaoImpl();
//3、调用studao实例的方法进行测试
//studao.xxxxx(stu);
stu.setStu_name("1");
int n = studao.deleteStudentByName(stu);
if(n > 0){
System.out.println("成功删除了"+n+"条数据!");
}else {
System.out.println("删除失败!");
}
}
}

  1. 关联映射

操作多张联合表

  • 栗子

(1) 导入jar包maven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<?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>chapter_8</groupId>
<artifactId>SSM_Test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>SSM_Test 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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.7</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-CR2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>3.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>SSM_Test</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>

(2) 一对一映射文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.PersonMapper">
<!-- 嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
<select id="findPersonById" parameterType="Integer"
resultMap="IdCardWithPersonResult">
SELECT * from tb_person where id=#{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="sex" column="sex" />
<!-- 一对一:association使用select属性引入另外一条SQL语句 -->
<association property="card" column="card_id" javaType="IdCard"
select="com.itheima.mapper.IdCardMapper.findCodeById" />
</resultMap>

<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 -->
<select id="findPersonById2" parameterType="Integer"
resultMap="IdCardWithPersonResult2">
SELECT p.*,idcard.code
from tb_person p,tb_idcard idcard
where p.card_id=idcard.id
and p.id= #{id}
</select>
<resultMap type="Person" id="IdCardWithPersonResult2">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<result property="sex" column="sex" />
<association property="card" javaType="IdCard">
<id property="id" column="card_id" />
<result property="code" column="code" />
</association>
</resultMap>

</mapper>

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.IdCardMapper">
<!-- 根据id查询证件信息 -->
<select id="findCodeById" parameterType="Integer" resultType="IdCard">
SELECT * from tb_idcard where id=#{id}
</select>
</mapper>

(3) 一对多关系映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace表示命名空间 -->
<mapper namespace="com.itheima.mapper.UserMapper">
<!-- 一对多:查看某一用户及其关联的订单信息
注意:当关联查询出的列名相同,则需要使用别名区分 -->
<select id="findUserWithOrders" parameterType="Integer"
resultMap="UserWithOrdersResult">
SELECT u.*,o.id as orders_id,o.number
from tb_user u,tb_orders o
WHERE u.id=o.user_id
and u.id=#{id}
</select>
<resultMap type="User" id="UserWithOrdersResult">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
<!-- 一对多关联映射:collection
ofType表示属性集合中元素的类型,List<Orders>属性即Orders类 -->
<collection property="ordersList" ofType="Orders">
<id property="id" column="orders_id"/>
<result property="number" column="number"/>
</collection>
</resultMap>
</mapper>

(4) 多对多关系映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.OrdersMapper">
<!-- 多对多嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
<select id="findOrdersWithPorduct" parameterType="Integer"
resultMap="OrdersWithProductResult">
select * from tb_orders WHERE id=#{id}
</select>
<resultMap type="Orders" id="OrdersWithProductResult">
<id property="id" column="id" />
<result property="number" column="number" />
<collection property="productList" column="id" ofType="Product"
select="com.itheima.mapper.ProductMapper.findProductById">
</collection>
</resultMap>

<!-- 多对多嵌套结果查询:查询某订单及其关联的商品详情 -->
<select id="findOrdersWithPorduct2" parameterType="Integer"
resultMap="OrdersWithPorductResult2">
select o.*,p.id as pid,p.name,p.price
from tb_orders o,tb_product p,tb_ordersitem oi
WHERE oi.orders_id=o.id
and oi.product_id=p.id
and o.id=#{id}
</select>
<!-- 自定义手动映射类型 -->
<resultMap type="Orders" id="OrdersWithPorductResult2">
<id property="id" column="id" />
<result property="number" column="number" />
<!-- 多对多关联映射:collection -->
<collection property="productList" ofType="Product">
<id property="id" column="pid" />
<result property="name" column="name" />
<result property="price" column="price" />
</collection>
</resultMap>

</mapper>

(5) 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import edu.hhtc.jsj.pojo.Cource;
import edu.hhtc.jsj.pojo.Student;
import edu.hhtc.jsj.pojo.Teacher;
import edu.hhtc.jsj.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MybatisAssociatedTest {
/**
* 一对一关联
* 功能:通过提供一个学生的学号,查找该学生,输出学生的相关信息和关联对象的相关信息,如学生证信息和学生所在班信息
*/
@Test
public void findStudentByIdTest() {
// 1、通过工具类生成SqlSession对象
SqlSession session = MybatisUtils.getSession();
// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
String id="180306702";
Student student = session.selectOne("mapper.StudentMapper.findStudentById",id );
// 3、输出查询结果信息
System.out.println("学号:"+student.getId()+"姓名:"+student.getName());
// System.out.println(student.getCard());
// System.out.println(student.getClasses());
System.out.println("学生证编号:"+student.getCard().getCar_id()+"发放单位:"+student.getCard().getPublisher());
System.out.println("班级:"+student.getClasses().getName());
// 4、关闭SqlSession
session.close();
}

/**
* 一对多关联
* 功能:通过提供一个学生的学号,查找该学生,再通过该学生的所在班级成员得到班级,输出该班全体学生信息
*
*/
@Test
public void findStudentesByStuIdTest() {
// 1、通过工具类生成SqlSession对象
SqlSession session = MybatisUtils.getSession();
// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
Student student = session.selectOne("mapper.StudentMapper.findStudentById", "180306703");
// 3、输出查询结果信息
System.out.println("班级编号:"+student.getClasses().getC_id()+" 班级名称:"+student.getClasses().getName());
List<Student> stulist=student.getClasses().getStudentlist();
for(Student stu:stulist) {
System.out.println("学号:"+stu.getId()+"姓名:"+stu.getName());

}
// 4、关闭SqlSession
session.close();
}

/**
* 多对多嵌套查询
* 功能:通过提供一课程的编号,查找该课程,输出该课程的授课教师信息
*
*/
@Test
public void findTeacherOfCourceByCourceIdTest() {
// 1、通过工具类生成SqlSession对象
SqlSession session = MybatisUtils.getSession();
// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
Cource cource = session.selectOne("mapper.CourceMapper.findCourceWithTeacherById", "11112");
// 3、输出查询结果信息
System.out.println(cource);
System.out.println("课程编号:"+cource.getCource_id()+" 姓名:"+cource.getName()+" 课程学分:"+cource.getCredit());
List<Teacher> tlist=cource.getTeacherlist();
for(Teacher t:tlist) {
System.out.println("教师工号:"+t.getTeacher_id()+" 姓名:"+t.getName()+" 职称:"+t.getRanks());

}
// 4、关闭SqlSession
session.close();
}

/**
* 多对多嵌套结果查询
* 功能:通过提供一教师的编号,查找该教师所承担的课程
*
*/
@Test
public void findCourceOfTeacherByTeacherIdTest() {
// 1、通过工具类生成SqlSession对象
SqlSession session = MybatisUtils.getSession();
// 2.使用MyBatis嵌套查询的方式查询id为1的人的信息
Teacher teacher = session.selectOne("mapper.TeacherMapper.findTeacherWithCourceByteacherId", "06003");
// 3、输出查询结果信息
System.out.println("教师工号:"+teacher.getTeacher_id()+" 姓名:"+teacher.getName()+" 职称:"+teacher.getRanks());
List<Cource> clist=teacher.getCourcelist();
for(Cource c:clist) {
System.out.println("课程编号:"+c.getCource_id()+" 课程名称:"+c.getName()+" 课程学分:"+c.getCredit());
}
// 4、关闭SqlSession
session.close();
}



}


  1. Spring与MyBatis整合

  2. maven导包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<?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>org.example</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>


<dependencies>
<!-- 核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>


<!-- AOP -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>


<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>


<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.8.0</version>
</dependency>



<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>

</project>

(2) log4j.properties控制台输出

1
2
3
4
5
6
7
8
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.itheima=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

(3)db.properties文件

1
2
3
4
5
6
7
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
jdbc.maxTotal=30
jdbc.maxIdle=10
jdbc.initialSize=5

(4) applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!--读取db.properties -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置数据源 -->
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource">
<!--数据库驱动 -->
<property name="driverClassName" value="${jdbc.driver}" />
<!--连接数据库的url -->
<property name="url" value="${jdbc.url}" />
<!--连接数据库的用户名 -->
<property name="username" value="${jdbc.username}" />
<!--连接数据库的密码 -->
<property name="password" value="${jdbc.password}" />
<!--最大连接数 -->
<property name="maxTotal" value="${jdbc.maxTotal}" />
<!--最大空闲连接 -->
<property name="maxIdle" value="${jdbc.maxIdle}" />
<!--初始化连接数 -->
<property name="initialSize" value="${jdbc.initialSize}" />
</bean>
<!-- 事务管理器,依赖于数据源 -->
<bean id="transactionManager" class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--开启事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--配置MyBatis工厂 -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据源 -->
<property name="dataSource" ref="dataSource" />
<!--指定核心配置文件位置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

<!--实例化Dao -->
<bean id="customerDao" class="com.itheima.dao.impl.CustomerDaoImpl">
<!-- 注入SqlSessionFactory对象实例-->
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- Mapper代理开发(基于MapperFactoryBean) -->
<!-- <bean id="customerMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.itheima.mapper.CustomerMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean> -->
<!-- Mapper代理开发(基于MapperScannerConfigurer) -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.mapper" />
</bean>

<!-- 开启扫描 -->
<context:component-scan base-package="com.itheima.service" />

</beans>

(5) mybatis-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置别名 -->
<typeAliases>
<package name="com.itheima.po" />
</typeAliases>
<!--配置Mapper的位置 -->
<mappers>
<mapper resource="com/itheima/po/CustomerMapper.xml" />
<!-- Mapper接口开发方式 -->
<mapper resource="com/itheima/mapper/CustomerMapper.xml" />

</mappers>
</configuration>

(6) 持久层

(7) DAO层接口和映射文件

(8) DAO实现类

(9) Service层和实现层

(10) 测试

9. Sprinng MVC

轻量级web框架

  1. 栗子

(1)maven导入新包

  • spring-web-4.3.6.RELEASE.jar
  • spring-webmvc-4.3.6.RELEASE.jar

(2)配置文件web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<!-- 配置前端过滤器 -->
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 初始化时加载配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<!-- 表示容器在启动时立即加载Servlet -->
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>



</web-app>

(3) entity

(4) DAO和映射文件

(5) Service和实现类

(6) 创建Controller类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package edu.hhtc.jsj.controller;

import edu.hhtc.jsj.convert.DateFormatter;
import edu.hhtc.jsj.pojo.CourceTable;
import edu.hhtc.jsj.pojo.CourceTableVO;
import edu.hhtc.jsj.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;
import java.util.List;
import java.util.Locale;

@Controller("/mycontroller")
@RequestMapping("/mycontroller")
public class MyController {
@RequestMapping("/index")
public String fistRequest() {

return "index";
}

@RequestMapping("/login")
public String secondRequest(User user) {
// 输出user的成员值
String id = user.getId();
String username = user.getUsername();
String password = user.getPassword();
System.out.println("id=" + id);
System.out.println("username=" + username);
System.out.println("password=" + password);
return "interest";
}

@RequestMapping("/registerInterest")
public String registerInterest(String[] interests) {
// 输出user的成员值
if(interests != null){
for (String interest : interests){
System.out.println("项目兴趣选择了" + interest);
}
}else {
System.out.println("兴趣为空!");
}
return "date";
}
@RequestMapping("/registerdatetime")
public String registerDateTime(Date date){
// 输出date的值

System.out.println("date=" + date);
return "courcetable";
}

@RequestMapping("/addCourcetable")
public String registerDateTime(CourceTableVO courcetables) {
// 输出周课表的信息
List<CourceTable> courceTables = courcetables.getCourcetables();
for (CourceTable courceTable : courceTables) {
if((Integer)courceTable.getId() != null){
System.out.println("增加的课表id:" + courceTable.getId() + "增加的课表星期:" + courceTable.getWeekday() + "增加的课表时间:" + courceTable.getCourcetime() + "增加的课表名字:" + courceTable.getCourcename() + "增加的课表地址:" + courceTable.getAddress());
}
}
return "index";
}


}



(7) springmvc-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?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:mvc="http://www.springframework.org/schema/mvc"
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.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 指定需要扫描的包 -->
<context:component-scan base-package="edu.hhtc.jsj.controller" />
<!-- 定义视图解析器 -->
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 设置后缀 -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 显示的装配自定义类型转换器 -->
<mvc:annotation-driven conversion-service="conversionService" />
<!-- 自定义类型转换器配置 -->
<!-- <bean id="conversionService" class=
"org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itheima.convert.DateConverter" />
</set>
</property>
</bean> -->
<!-- 自定义类型格式化转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="edu.hhtc.jsj.convert.DateFormatter" />
</set>
</property>
</bean>
<!--@Controller("/mycontroller")相当于-->
<!-- 配置处理器Handle,映射“/firstController”请求 -->
<!--<bean name="/firstController"
class="com.itheima.controller.FirstController" />-->
<!-- 处理器映射器,将处理器Handle的name作为url进行查找 -->
<!-- <bean class=
"org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />-->
<!-- 处理器适配器,配置对处理器中handleRequest()方法的调用-->
<!-- <bean class=
"org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />-->
<!-- 视图解析器 -->
<!-- <bean class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>-->
</beans>

(8) View页面

(9) 时间格式化工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package edu.hhtc.jsj.convert;

import org.springframework.cglib.core.Local;
import org.springframework.format.Formatter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class DateFormatter implements Formatter<Date> {
//定义日期格式
String datePattern = "yyyy-MM-dd HH:mm:ss" ;
//声明SimpleDateFormat对象
private SimpleDateFormat simpleDateFormat;
@Override
public String print(Date date, Locale locale){
return new SimpleDateFormat().format(date);
}
@Override
public Date parse(String source,Locale locale) throws ParseException{
simpleDateFormat = new SimpleDateFormat(datePattern);
return simpleDateFormat.parse(source);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.itheima.convert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
* 自定义日期转换器
*/
public class DateConverter implements Converter<String, Date> {
// 定义日期格式
private String datePattern = "yyyy-MM-dd HH:mm:ss";
@Override
public Date convert(String source) {
// 格式化日期
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
try {
return sdf.parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException(
"无效的日期格式,请使用这种格式:"+datePattern);
}
}
}

  1. 工作流程

image-20210701004845439

  1. 核心类与注解
  • DispatcherServlet(前端控制器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//在web.xml文件中
<servlet>
<!-- 配置前端过滤器 -->
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 初始化时加载配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<!-- 表示容器在启动时立即加载Servlet -->
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
  • @Controller

表明类是一个控制器

注意:

1
2
3
<!-- 1.指定需要扫描的包 -->
<context:component-scan base-package="com.itheima.controller" />
<!--2.使用注解时,程序运行依赖于Spring的AOP包-->
  • @RequestMapping(value=”/hello”,method =RequestMethod.GET)

  • 参数类型:Model,数据类型,HttpServletRequest,HttpServletResponse,HttpSession

  • 返回值类型:String【视图】+参数【Model】、ModelAndView【未解耦】、void【数据,异步请求】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.itheima.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 控制器类
*/
@Controller
@RequestMapping(value="/hello",method =RequestMethod.GET)
public class FirstController{
@RequestMapping(value="/firstController")
public String handleRequest(HttpServletRequest request,
HttpServletResponse response, Model model,HttpSession ) throws Exception {
// 向模型对象中添加数据
model.addAttribute("msg", "这是我的第一个Spring MVC程序");
// 返回视图页面
return "first";
}
}

  • redirect【重定向】+forward【请求转发,修改】

  • 视图解析器

简化view路径

1
2
3
4
5
6
7
8
<!-- 定义视图解析器 -->
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 设置后缀 -->
<property name="suffix" value=".jsp" />
</bean>

10. 数据绑定

  1. 注解
  • @RequestParam绑定单个请求参数值;

  • @PathVariable绑定URI模板变量值;

  • @CookieValue绑定Cookie数据值

  • @RequestHeader绑定请求头数据;

  • @ModelValue绑定参数到命令对象;

  • @SessionAttributes绑定命令对象到session;

  • @RequestBody绑定请求的内容区数据并能进行自动类型转换等,例如JSON和RESTful风格。

  • @RequestPart绑定“multipart/data”数据,除了能绑定@RequestParam能做到的请求参数外,还能绑定上传的文件等。

  • 除了上边提到的注解,我们还可以通过如HttpServletRequest等API得到请求数据,但推荐使用注解方式,因为使用起来更简单。

  1. 流程

image-20210701132530041

  1. 简单数据绑定
  • 基本数据类型
1
2
3
4
5
@RequestMapping("/selectUser")
public String selectUser(@RequestParam(value="user_id")Integer id) {
System.out.println("id="+id);
return "success";
}
  • POJO类型
1
2
3
4
5
6
7
8
9
10
11
/**
* 接收用户注册信息
*/
@RequestMapping("/registerUser")
public String registerUser(User user) {
String username = user.getUsername();
Integer password = user.getPassword();
System.out.println("username="+username);
System.out.println("password="+password);
return "success";
}
  • 乱码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 配置编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
  • 包装类POJO

前端的name值如果是POJO子属性,应为:对象.属性 例如user.username

(1) entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.itheima.po;
/**
* 订单POJO
*/
public class Orders {
private Integer ordersId; // 订单编号
private User user; // 用户POJO,所属用户
public Integer getOrdersId() {
return ordersId;
}
public void setOrdersId(Integer ordersId) {
this.ordersId = ordersId;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}

(2) Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.itheima.po.Orders;
import com.itheima.po.User;
@Controller
public class OrdersController {
/**
* 向订单查询页面跳转
*/
@RequestMapping("/tofindOrdersWithUser")
public String tofindOrdersWithUser( ) {
return "orders";
}
/**
* 查询订单和用户信息
*/
@RequestMapping("/findOrdersWithUser")
public String findOrdersWithUser(Orders orders) {
Integer orderId = orders.getOrdersId();
User user = orders.getUser();
String username = user.getUsername();
System.out.println("orderId="+orderId);
System.out.println("username="+username);
return "success";
}
}

(3) 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>订单查询</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/findOrdersWithUser"
method="post">
订单编号:<input type="text" name="ordersId" /><br />
所属用户:<input type="text" name="user.username" /><br />
<input type="submit" value="查询" />
</form>
</body>
</html>

  • 自定义数据绑定

(1) 自定义日期转换器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.itheima.convert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
* 自定义日期转换器
*/
public class DateConverter implements Converter<String, Date> {
// 定义日期格式
private String datePattern = "yyyy-MM-dd HH:mm:ss";
@Override
public Date convert(String source) {
// 格式化日期
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
try {
return sdf.parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException(
"无效的日期格式,请使用这种格式:"+datePattern);
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.itheima.convert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import org.springframework.format.Formatter;
/**
* 使用Formatter自定义日期转换器
*/
public class DateFormatter implements Formatter<Date>{
// 定义日期格式
String datePattern = "yyyy-MM-dd HH:mm:ss";
// 声明SimpleDateFormat对象
private SimpleDateFormat simpleDateFormat;
@Override
public String print(Date date, Locale locale) {
return new SimpleDateFormat().format(date);
}
@Override
public Date parse(String source, Locale locale) throws ParseException
{
simpleDateFormat = new SimpleDateFormat(datePattern);
return simpleDateFormat.parse(source);
}
}

(2) Spring MVC配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 自定义类型转换器配置 -->
<!-- <bean id="conversionService" class=
"org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itheima.convert.DateConverter" />
</set>
</property>
</bean> -->
<!-- 自定义类型格式化转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="com.itheima.convert.DateFormatter" />
</set>
</property>
</bean>

(3) Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itheima.controller;
import java.util.Date;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 日期控制器类
*/
@Controller
public class DateController {
/**
* 使用自定义类型数据绑定日期数据
*/
@RequestMapping("/customDate")
public String CustomDate(Date date) {
System.out.println("date="+date);
return "success";
}
}

  1. 复杂数据绑定
  • 绑定数组

(1) 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>爱好选择</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/mycontroller/registerInterest"
method="post">
<table width="80%" border=1>
<tr>
<td width="10%">项目</td>
<td width="90%">选择</td>
</tr>
<tr>
<td>兴趣</td>
<td>
<input type="checkbox" name="interests" value="篮球">篮球&nbsp&nbsp
<input type="checkbox" name="interests" value="游戏">游戏&nbsp&nbsp
<input type="checkbox" name="interests" value="上网">上网&nbsp&nbsp
<input type="checkbox" name="interests" value="旅游">旅游&nbsp&nbsp
<input type="checkbox" name="interests" value="羽毛球">羽毛球&nbsp&nbsp
<input type="checkbox" name="interests" value="舞蹈">舞蹈&nbsp&nbsp
</td>
</tr>

</table>
<input type="submit" value="提交"/>
</form>
</body>
</html>

(2) Controller

1
2
3
4
5
6
7
8
9
10
11
12
@RequestMapping("/registerInterest")
public String registerInterest(String[] interests) {
// 输出user的成员值
if(interests != null){
for (String interest : interests){
System.out.println("项目兴趣选择了" + interest);
}
}else {
System.out.println("兴趣为空!");
}
return "date";
}
  • 绑定集合

(1) 包装类UserVo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.itheima.vo;
import java.util.List;
import com.itheima.po.User;
/**
* 用户包装类
*/
public class UserVO {
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}

(2) 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改用户</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/editUsers"
method="post" id='formid'>
<table width="30%" border=1>
<tr>
<td>选择</td>
<td>用户名</td>
</tr>
<tr>
<td>
<input name="users[0].id" value="1" type="checkbox" />
</td>
<td>
<input name="users[0].username" value="tome" type="text" />
</td>
</tr>
<tr>
<td>
<input name="users[1].id" value="2" type="checkbox" />
</td>
<td>
<input name="users[1].username" value="jack" type="text" />
</td>
</tr>
</table>
<input type="submit" value="修改" />
</form>
</body>
</html>

(3) Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 向用户批量修改页面跳转
*/
@RequestMapping("/toUserEdit")
public String toUserEdit() {
return "user_edit";
}
/**
* 接收批量修改用户的方法
*/
@RequestMapping("/editUsers")
public String editUsers(UserVO userList) {
// 将所有用户数据封装到集合中
List<User> users = userList.getUsers();
// 循环输出所有用户信息
for (User user : users) {
// 如果接收的用户id不为空,则表示对该用户进行了修改
if(user.getId() !=null){
System.out.println("修改了id为"+user.getId()+
"的用户名为:"+user.getUsername());
}
}
return "success";
}

11. JSON数据交互与RESTful支持

  1. JSON数据转化

(1)导入新包

  • jackson-annotations-2.8.8.jar
  • jackson-core-2.8.8.jar
  • jackson-databind-2.8.8.jar

(2) 注解

  • @ResponseBody:直接返回return对象,用于method
  • @RequestBody:用于请求的数据绑定到方法的形参中,用于形参上

(3) web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>chapter14</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置Spring MVC前端控制器 DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 配置Spring MVC加载配置文件路径 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<!-- 配置服务器启动后立即加载Spring MVC配置文件 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!--激活tomcat的静态资源拦截,需要哪些静态文件,再往下追加-->
<!-- <servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping> -->

</web-app>

(4) springMVC配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 定义组件扫描器,指定需要扫描的包 -->
<context:component-scan base-package="com.itheima.controller" />
<!-- 配置注解驱动 -->
<mvc:annotation-driven />

<!--配置静态资源的访问映射,此配置中的文件,将不被前端控制器拦截 -->
<mvc:resources location="/js/" mapping="/js/**" />
<!-- <mvc:default-servlet-handler /> -->

<!-- 配置视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

<!-- <bean>标签配置注解方式的处理器映射器和处理器适配器必须配对使用 -->
<!-- 使用<bean>标签配置注解方式的处理器映射器 -->
<!-- <bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
使用<bean>标签配置注解方式的处理器适配器
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
在注解适配器中配置JSON转换器
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean> -->

</beans>

(5) entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.itheima.po;
/**
* 用户POJO
*/
public class User {
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;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}

(6) Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.itheima.po.User;
@Controller
public class UserController {
/**
* 接收页面请求的JSON数据,并返回JSON格式结果
*/
@RequestMapping("/testJson")
@ResponseBody
public User testJson(@RequestBody User user) {
// 打印接收的JSON格式数据
System.out.println(user);
// 返回JSON格式的响应
return user;
}

/**
*接收RESTful风格的请求,其接收方式为GET
*/
@RequestMapping(value="/user/{id}",method=RequestMethod.GET)
@ResponseBody
public User selectUser(@PathVariable("id") String id){
//查看数据接收
System.out.println("id="+id);
User user=new User();
//模拟根据id查询出到用户对象数据
if(id.equals("1234")){
user.setUsername("tom");
}
//返回JSON格式的数据
return user;
}

}

(7) 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<%--
Created by IntelliJ IDEA.
User: xxy
Date: 2021/4/20
Time: 22:06
To change this template use File | Settings | File Templates.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js">
</script>
<script type="text/javascript">
function testJson(){
// 获取输入的用户名和密码
var username =$("#username").val();
var password =$("#password").val();

$.ajax({
url : "${pageContext.request.contextPath }/testJson",
type : "post",
// data表示发送的数据
data :JSON.stringify({username:username,password:password}),
// 定义发送请求的数据格式为JSON字符串
contentType : "application/json;charset=UTF-8",
//定义回调响应的数据格式为JSON字符串,该属性可以省略
dataType : "json",
//成功响应的结果
success : function(data){
if(data != null){
//将data的结果提取并显示到页面定义的div页面上,每个数据单独使用一行显示。
alert("你输入的用户名为:" + data.username + "你输入的密码为:" + data.password);
}
}
});
}
</script>
<html>
<head>
<title>JSON提交</title>
</head>
<body>
<form>
用户名:<input type="text" name="username" id="username"><br />
密&nbsp;&nbsp;&nbsp;码:
<input type="password" name="password" id="password"><br />
<input type="button" value="测试JSON交互" onclick=" testJson()" />
</form>


</body>
</html>

  1. RESTful风格

一种请求路径的风格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<%--
Created by IntelliJ IDEA.
User: xxy
Date: 2021/4/20
Time: 22:06
To change this template use File | Settings | File Templates.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript"
src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js">
</script>
<script type="text/javascript">
function testJson1(){
// 获取输入的用户名和密码
var username =$("#username").val();
var password =$("#password").val();

$.ajax({
url : "${pageContext.request.contextPath }/testJson1"+"/" + username + "/" + password,
type : "get",
// data表示发送的数据
/* data :JSON.stringify({username:username,password:password}),*/
// 定义发送请求的数据格式为JSON字符串
/*contentType : "application/json;charset=UTF-8",*/
//定义回调响应的数据格式为JSON字符串,该属性可以省略
dataType : "json",
//成功响应的结果
success : function(data){
if(data != null){
//将data的结果提取并显示到页面定义的div页面上,每个数据单独使用一行显示。
/*alert("你输入的用户名为:" + username + "你输入的密码为:" + password);*/
$("#test").html("你输入的用户名为:" + data.username + "你输入的密码为:" + password);
}
}
});
}
</script>
<html>
<head>
<title>JSON提交</title>
</head>
<body>
<form>
用户名:<input type="text" name="username" id="username"><br />
密&nbsp;&nbsp;&nbsp;码:
<input type="password" name="password" id="password"><br />
<input type="button" value="测试JSON交互" onclick=" testJson1()" />
</form>
<div id="test" name="test">

</div>

</body>
</html>

12. 拦截器

类似于过滤器,用于拦截用户请求,做出相应处理;顺序postHandle,afterCompletion与拦截器顺序相反

  • 栗子

(1) 设置拦截器1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package edu.hhtc.jsj.interceptor;

import edu.hhtc.jsj.pojo.Student;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class MonitorInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {


HttpSession session = httpServletRequest.getSession();
Student student = (Student) session.getAttribute("STUDENT_SESSION");
if(student.getPosition() == "monitor"){
return true;
}
httpServletRequest.setAttribute("msg","不好意思,您还不是班长,请先当选班长!");

httpServletRequest.getRequestDispatcher("/WEB-INF/jsp/student/main_stu.jsp").forward(httpServletRequest,httpServletResponse);

return false;
}

@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

}
}

(2) 设置拦截器2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package edu.hhtc.jsj.interceptor;

import edu.hhtc.jsj.pojo.Teacher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class PrincipalInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
HttpSession session = httpServletRequest.getSession();
Teacher teacher = (Teacher) session.getAttribute("TEACHER_SESSION");
if(teacher.getPosition() == "principal"){
return true;
}
httpServletRequest.setAttribute("msg","不好意思,您还不是教研室主任!");

httpServletRequest.getRequestDispatcher("/WEB-INF/jsp/teacher/main_teacher.jsp").forward(httpServletRequest,httpServletResponse);

return false;
}

@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

}
}

(3) 设置拦截器3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package edu.hhtc.jsj.interceptor;

import edu.hhtc.jsj.pojo.Teacher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class TeacherInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {

String url = httpServletRequest.getRequestURI();

HttpSession session = httpServletRequest.getSession();
Teacher teacher = (Teacher) session.getAttribute("TEACHER_SESSION");
if(teacher != null){
return true;
}
httpServletRequest.setAttribute("msg","您还没有登录,请先登录!");

httpServletRequest.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(httpServletRequest,httpServletResponse);

return false;
}

@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

}

@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

}
}

(4) SpringMVC配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?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:mvc="http://www.springframework.org/schema/mvc"
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.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 指定需要扫描的包 -->
<context:component-scan base-package="edu.hhtc.jsj.controller" />
<!--配置注解驱动-->
<mvc:annotation-driven />
<!-- 配置静态资源的访问映射,此配置中的文件,将不被前端控制器拦截-->
<mvc:resources mapping="/js/**" location="/js/" />
<!-- 定义视图解析器 -->
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 设置后缀 -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 显示的装配自定义类型转换器 -->
<!-- <mvc:annotation-driven conversion-service="conversionService" />-->
<!-- 自定义类型转换器配置 -->
<!-- <bean id="conversionService" class=
"org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.itheima.convert.DateConverter" />
</set>
</property>
</bean> -->
<!-- 自定义类型格式化转换器配置 -->
<!-- <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="edu.hhtc.jsj.convert.DateFormatter" />
</set>
</property>
</bean>-->
<!-- 配置拦截器 -->
<mvc:interceptors>
<!--使用bean直接定义在<mvc:interceptors>下面的拦截器将拦截所有请求-->
<!-- <bean class="xxx.xxx.interceptor.XXXInterceptor"/> -->
<!-- 拦截器1 -->
<mvc:interceptor>
<mvc:mapping path="/student/**" />
<!-- 定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截的 > -->
<bean class="edu.hhtc.jsj.interceptor.StudentInterceptor" />
</mvc:interceptor>
<!-- 拦截器2 -->
<mvc:interceptor>
<mvc:mapping path="/student/monitor/**" />
<!-- 定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截的 > -->
<bean class="edu.hhtc.jsj.interceptor.MonitorInterceptor" />
</mvc:interceptor>

<!-- 拦截器2 -->
<mvc:interceptor>
<mvc:mapping path="/teacher/**" />
<!-- 定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截的 > -->
<bean class="edu.hhtc.jsj.interceptor.TeacherInterceptor" />
</mvc:interceptor>
<!-- 拦截器2 -->
<mvc:interceptor>
<mvc:mapping path="/teacher/principal/**" />
<!-- 定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截的 > -->
<bean class="edu.hhtc.jsj.interceptor.PrincipalInterceptor" />
</mvc:interceptor>
</mvc:interceptors>

</beans>

(5) 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%--
Created by IntelliJ IDEA.
User: xxy
Date: 2021/4/21
Time: 15:38
To change this template use File | Settings | File Templates.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<html>
<head>
<title>登录界面</title>
</head>
<body>
${msg}
<form action="${pageContext.request.contextPath }/login"
method="POST">
用户类型:<select name="usertype" style="width:130px">
<option value="student">学生</option>
<option value="teacher">教师</option>
<option/>
</select> <br />
用户编号:<input type="text" name="userid" style="width:130px"/><br />
密&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;码:
<input type="password" name="password" style="width:130px"/><br />
<input type="submit" value="登录" />
</form>

</body>
</html>

13. 文件上传和下载

  1. 上传与下载

(1)导入新包

  • commons-io-2.5.jar
  • hamcrest-core-1.3.jar

(2) SringMVC配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:resources location="/js/" mapping="/js/**" />
<mvc:resources mapping="/UpLoadFile/**" location="/UpLoadFile/" />
<mvc:resources mapping="/DowLoadFile/**" location="/DowLoadFile/" />
<context:component-scan base-package="edu.hhtc.jsj.controller" />
<!-- 定义视图解析器 -->
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置前缀 -->
<!-- <property name="prefix" value="/WEB-INF/jsp/" />-->
<!-- &lt;!&ndash; 设置后缀 &ndash;&gt;-->
<!-- <property name="suffix" value=".jsp" />-->
</bean>
<mvc:annotation-driven />
<!-- 配置文件上传解析器 MultipartResolver -->
<bean id="multipartResolver" class= "org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置请求编码格式-->
<property name="defaultEncoding" value="UTF-8" />
<!-- 设置上传文件最大长度-->
<property name="maxUploadSize" value="2097152" />
<!-- 设置推迟文件解析-->
<property name="resolveLazily" value="true" />
</bean>




</beans>

(2) 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@page import="java.net.URLEncoder"%>
<%@page import="java.util.*"%>
<%@page import="java.lang.*"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">


<html>
<head>
<title>上传文件</title>
</head>
<body>
上传文件<br>
<form action="${pageContext.request.contextPath }/uploadfile" method="POST" enctype="multipart/form-data" onsubmit="return check()">
请选择文件:<input id="file" type="file" name="uploadfile" multiple="multiple" /><br />
<input type="submit" value="上传" />
</form>
文件下载显示内容:
下载:<br>
<c:if test="${not empty filelist}">
<c:forEach var="s" items="${filelist}">
<a href="${pageContext.request.contextPath}//downloadfile?filename=${s}">${s}</a><br/>
</c:forEach>
<%-- <c:set var="filelist" value="${filelist}" scope="request"></c:set>--%>

<%-- <c:set var="path" value="${pageContext.request.contextPath }" scope="request"></c:set>--%>
<%-- <%--%>
<%-- List<String> filelist=(List<String>)request.getAttribute("filelist");--%>
<%-- for(String filename:filelist){--%>
<%-- System.out.print("<a href=\""+request.getAttribute("path")+"/download?filename="+URLEncoder.encode(filename, "UTF-8")+"\">");--%>
<%-- System.out.print(filename+"</a><br>");--%>
<%-- }--%>
<%-- %>--%>
</c:if>

<script>
// 判断是否已选择上传文件
function check(){
var file = document.getElementById("file").value;
if(file.length==0||file==""){
alert("请选择上传文件");
return false;
}
return true;
}
</script>
</body>

</html>

(3) Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package edu.hhtc.jsj.controller;

import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

@Controller
public class FileUpandDownController{
/**
* 文件上传 接收文件后返回upanddownfile.jsp页面
* 由于页面在跟目录下,不能使用视图解析器,必须通过ModeandView定制返回响应页面和下载文件名数据
*/
@RequestMapping(value = "upanddownfile",method = RequestMethod.GET)
public ModelAndView index(HttpServletRequest request){
List<String> filelist = new ArrayList<String>();
String dirPath = request.getServletContext().getRealPath("/DowLoadFile/");
File filePath = new File(dirPath);
if(!filePath.exists()){
filePath.mkdirs();
}
for(File file1 : filePath.listFiles()){
filelist.add(file1.getName());
}
// 创建ModelAndView对象
ModelAndView mav = new ModelAndView();
// 向模型对象中添加数据
mav.addObject("filelist", filelist);
// 设置逻辑视图名
mav.setViewName("upanddownfile.jsp");
return mav;
}

@RequestMapping(value="/uploadfile",method= RequestMethod.POST)
public ModelAndView uploadfile(@RequestParam("uploadfile") List<MultipartFile> uploadfile,
HttpServletRequest request) {
//为了提供下载文件 创建一个List存储上传的文件名
List<String> filelist=new ArrayList<String>();
//处理流程
//1.通过uploadfile的遍历处理每个上传文件,并将文件名加入filelist
//2.将文件以源文件名保存到UpLoadFile文件夹下
if(!uploadfile.isEmpty() && uploadfile.size() > 0){
for(MultipartFile file : uploadfile){
String orginalFilename = file.getOriginalFilename();
String dirPath = request.getServletContext().getRealPath("/DowLoadFile/");
File filePath = new File(dirPath);
filelist.add(orginalFilename);
if(!filePath.exists()){
filePath.mkdirs();
}
for(File file1 : filePath.listFiles()){
filelist.add(file1.getName());
}
String filename = orginalFilename;
try {
file.transferTo(new File(dirPath+filename));
System.out.println("上传成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 创建ModelAndView对象
ModelAndView mav = new ModelAndView();
// 向模型对象中添加数据
mav.addObject("filelist", filelist);
// 设置逻辑视图名
mav.setViewName("upanddownfile.jsp");
return mav;
}
/**
* 文件下载
*/
@RequestMapping(value="/downloadfile",method=RequestMethod.GET)
public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
String filename) throws Exception{
// 指定要下载的文件所在路径
String path = request.getServletContext().getRealPath("/DowLoadFile/");
// 创建该文件对象
File file = new File(path+File.separator+filename);
// 对文件名编码,防止中文文件乱码
filename = this.getFilename(request, filename);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
// 通知浏览器以下载的方式打开文件
headers.setContentDispositionFormData("attachment", filename);
// 定义以流的形式下载返回文件数据
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 使用Sring MVC框架的ResponseEntity对象封装返回下载数据
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
headers, HttpStatus.OK);
}
/**
* 根据浏览器的不同进行编码设置,返回编码后的文件名
*/
public String getFilename(HttpServletRequest request,
String filename) throws Exception {
// IE不同版本User-Agent中出现的关键词
String[] IEBrowserKeyWords = {"MSIE", "Trident", "Edge"};
// 获取请求头代理信息
String userAgent = request.getHeader("User-Agent");
for (String keyWord : IEBrowserKeyWords) {
if (userAgent.contains(keyWord)) {
//IE内核浏览器,统一为UTF-8编码显示
return URLEncoder.encode(filename, "UTF-8");
}
}
//火狐等其它浏览器统一为ISO-8859-1编码显示
return new String(filename.getBytes("UTF-8"), "ISO-8859-1");
}

}


14. SSM整合

  1. maven导入jar包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<?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>cn.com.byte1024</groupId>
<artifactId>VoteSystem</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<name>VoteSystem Maven Webapp</name>
<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>
<spring.version>4.1.9.RELEASE</spring.version>
<mybatis.version>3.2.6</mybatis.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>



<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</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>org.springframework</groupId>
<artifactId>spring-aop</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-test</artifactId>
<version>${spring.version}</version>
</dependency>

<!-- 映入JSON -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- 上传组件包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>

<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.1</version>

</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.5.0</version>

</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.0</version>

</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>

<!-- 连接mysql -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>

<!-- redis包 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.2.RELEASE</version>
</dependency>

<!-- 腾讯云短信平台-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.172</version>
</dependency>

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>

<!-- 引入jstlC标签-->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>

</dependencies>

<build>
<!-- 如果不添加此节点mybatis的mapper.xml文件都会被漏掉。 -->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>

  1. 文件组织结构

image-20210701210845702

  1. 数据库设置
  • 管理员表(tb_admin)
表名(中文) 表名(英文)
管理员表 tb_admin
字段名 数据类型 长度 备注 说明
user_id varchar 50 主键 用户id
login_name varchar 50 登录名
user_name varchar 255 用户名
password varchar 100 用户密码
phone varchar 11 手机号
email varchar 30 电子邮箱
user_state varchar 2 管理员状态
user_creatdata Datatime 创建时间
  • 用户表(tb_user)
表名(中文) 表名(英文)
用户表 tb_user
字段名 数据类型 长度 备注 说明
user_id varchar 50 主键 用户id
login_name varchar 50 登录名
user_name varchar 255 用户名
password varchar 100 用户密码
phone varchar 11 手机号
email varchar 30 电子邮箱
  • 数字字典表(tb_base_dict)
表名(中文) 表名(英文)
数字字典表 tb_base_dict
英文名称 数据类型 长度 备注 属性项名称
dict_id varchar 10 主键 数据字典id
dict_type_code varchar 10 数据字典类别代码
dict_type_name varchar 10 数据字典类别名称
dict_item_name varchar 10 数据字典项目名称
dict_item_code varchar 10 数据字典项目代码(可为空)
dict_sort int 11 排序字段
dict_enable varchar 2 是否可用:1:使用,0:停用
dict_memo varchar 50 备注
  1. log4j.properties【控制台输出】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
log4j.rootLogger=INFO,Console,File  
#定义日志输出目的地为控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
#可以灵活地指定日志输出格式,下面一行是指定具体的格式
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n

#文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.File = org.apache.log4j.RollingFileAppender
#指定输出目录
log4j.appender.File.File = logs/ssm.log
#定义文件最大大小
log4j.appender.File.MaxFileSize = 10MB
# 输出所以日志,如果换成DEBUG表示输出DEBUG以上级别日志
log4j.appender.File.Threshold = ALL
log4j.appender.File.layout = org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c]%m%n
  1. db.properties【数据库参数】
1
2
3
4
5
6
7
8
9
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/vote_system?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
jdbc.initialSize=0
jdbc.maxActive=20
jdbc.maxIdle=20
jdbc.minIdle=1
jdbc.maxWait=60000
  1. redis.properties【缓存参数】
1
2
3
4
5
6
7
8
9
10
11
12
redis.host=127.0.0.1
redis.port=6379
redis.password=root
redis.timeout=100000
redis.maxTotal=300
redis.maxIdle=200
redis.maxWait=10000
redis.testOnBorrow=true
redis.testOnReturn=true
# 默认缓存失效时间
defaultCacheExpireTime=3600

  1. resource.properties【字典dict_type_code的值】
1
2
3
customer.from.type=002
customer.industry.type=001
customer.level.type=006
  1. spring.xml【Spring配置文件,有redis】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?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: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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 自动扫描 -->
<context:component-scan base-package="cn.com.byte1024"/>

<context:property-placeholder location="classpath:db.properties" ignore-unresolvable="true"/>

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 初始化连接大小 -->
<property name="initialSize" value="${jdbc.initialSize}"></property>
<!-- 连接池最大数量 -->
<property name="maxActive" value="${jdbc.maxActive}"></property>
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="${jdbc.maxIdle}"></property>
<!-- 连接池最小空闲 -->
<property name="minIdle" value="${jdbc.minIdle}"></property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="${jdbc.maxWait}"></property>
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:cn/com/byte1024/mapper/*Mapper.xml"/>
<!-- 扫描包位置 -->
<!--当你设置这个 ,那么在Mybatis的Mapper文件里面就可以直接写对应的类名 而不用写全路径名了-->
<property name="typeAliasesPackage" value="cn.com.byte1024.entity" />
</bean>

<!-- mapper接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 给出需要扫描Mapper接口包 -->
<property name="basePackage" value="cn.com.byte1024.mapper"/>
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>


<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 配置事务 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 事务操作 -->
<tx:method name="get*" read-only="true" propagation="REQUIRED" />
<tx:method name="find*" read-only="true" propagation="REQUIRED" />
<tx:method name="select*" read-only="true" propagation="REQUIRED" />
<tx:method name="query*" read-only="true" propagation="REQUIRED" />
<!-- 设置非只读事务 -->
<tx:method name="*" read-only="false" />
</tx:attributes>
</tx:advice>

<!-- 配置AOP切面 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut expression="execution(* cn.com.byte1024.service.impl.*.*(..))" id="pt" />
<!-- 切面 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt" />
</aop:config>

<!-- 导入spring-redis.xml -->
<import resource="spring-redis.xml"/>


</beans>
  1. applicationContext.xml【不用缓存,Spring配置文件,可选】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans ">

<!-- 配置数据源-->
<context:property-placeholder location="classpath:db.properties" />
<bean id="dataSource" class=
"org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.ur}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxTotal" value="${jdbc.maxTotal}" />
<property name="maxIdle" value="${jdbc.maxIdle}" />
<property name="initialSize" value="${jdbc.initialSize}" />
</bean>

<!-- 配置事务管理,依赖数据源-->
<bean id="transactionManager" class=
"org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="find*" propagation="SUPPORTS"
read-only="true" />
<tx:method name="select*" propagation="SUPPORTS"
read-only="true" />
<tx:method name="get*" propagation="SUPPORTS"
read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* edu.hhtc.jsj.service.*.*(..))" />
</aop:config>
<!--mybatis sqlSessionFactory配置-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mappers/*.xml"/>
</bean>
<!--配置扫描dao接口包,mybatis动态实现dao接口,注入spring容器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="edu.hhtc.jsj.dao"/>
</bean>
<!-- 扫描service-->
<context:component-scan base-package="edu.hhtc.jsj.service" />

</beans>

  1. redis.properties【缓存参数】
1
2
3
4
5
6
7
8
9
10
11
12
redis.host=127.0.0.1
redis.port=6379
redis.password=root
redis.timeout=100000
redis.maxTotal=300
redis.maxIdle=200
redis.maxWait=10000
redis.testOnBorrow=true
redis.testOnReturn=true
# 默认缓存失效时间
defaultCacheExpireTime=3600

  1. mybatis-config.xml【Mybatis配置文件,无redis】
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="edu.hhtc.jsj.entity"/>
</typeAliases>

</configuration>

  1. spring-redis.xml【redis配置文件】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?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:aop="http://www.springframework.org/schema/aop"
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">

<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>

<!-- redis连接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxTotal" value="${redis.maxTotal}"/>
<property name="maxWaitMillis" value="${redis.maxWait}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
<property name="testOnReturn" value="${redis.testOnReturn}"/>
</bean>

<!-- redis连接工厂 -->
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="poolConfig" ref="jedisPoolConfig"/>

<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="password" value="${redis.password}"/>
<property name="timeout" value="${redis.timeout}"></property>
</bean>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory"/>

<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>

<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
</bean>

<!-- 缓存拦截器配置 -->
<bean id="methodCacheInterceptor" class="cn.com.byte1024.interceptor.MethodCacheInterceptor">
<property name="redisUtil" ref="redisUtil"/>
<property name="defaultCacheExpireTime" value="${defaultCacheExpireTime}"/>
<!-- 禁用缓存的类名列表 -->
<property name="targetNamesList">
<list>
<value></value>
</list>
</property>

<!-- 禁用缓存的方法名列表 -->
<property name="methodNamesList">
<list>
<value></value>
</list>
</property>
</bean>

<bean id="redisUtil" class="cn.com.byte1024.utils.RedisUtil">
<property name="redisTemplate" ref="redisTemplate"/>
</bean>

<!--配置切面拦截方法 -->
<!--<aop:config proxy-target-class="true">-->
<!--<aop:pointcut id="controllerMethodPointcut" expression="execution(* cn.com.byte1024.service.impl.*.list*(..))"/>-->
<!--<aop:advisor advice-ref="methodCacheInterceptor" pointcut-ref="controllerMethodPointcut"/>-->
<!--</aop:config>-->


</beans>

  1. springmvc-config.xml【springMVC配置文件,无redis】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 加载属性文件 -->
<context:property-placeholder
location="classpath:resource.properties" />
<!-- 配置扫描器 -->
<context:component-scan base-package="edu.hhtc.jsj.controller"/>
<!--mvc注解支持-->
<mvc:annotation-driven/>
<!-- 解除servlet对静态资源文件访问的限制 -->
<mvc:default-servlet-handler />
<!--配置静态资源的访问映射,此配置中的文件,将不被前端控制器拦截 -->
<mvc:resources location="/js/" mapping="/js/**" />
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/fonts/" mapping="/fonts/**" />
<mvc:resources location="/images/" mapping="/images/**" />

<!-- 定义视图解析器 -->
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 设置后缀 -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 配置文件上传解析器 MultipartResolver -->
<bean id="multipartResolver" class= "org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置请求编码格式-->
<property name="defaultEncoding" value="UTF-8" />
<!-- 设置上传文件最大长度-->
<property name="maxUploadSize" value="2097152" />
<!-- 设置推迟文件解析-->
<property name="resolveLazily" value="true" />
</bean>
<!-- 定义日期转换 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="edu.hhtc.jsj.util.DateFormatter" />
</set>
</property>
</bean>

<mvc:interceptors>
<!--使用bean直接定义在<mvc:interceptors>下面的拦截器将拦截所有请求-->
<!-- <bean class="xxx.xxx.interceptor.XXXInterceptor"/> -->
<!-- 拦截器1 -->
<mvc:interceptor>
<mvc:mapping path="/secretary/*" />
<!-- 定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截的 -->
<bean class="edu.hhtc.jsj.interceptor.SecretaryInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/*" />
<!-- 定义在<mvc:interceptor>下面的表示匹配指定路径的请求才进行拦截的 -->
<bean class="edu.hhtc.jsj.interceptor.LoginInterceptor" />
</mvc:interceptor>

</mvc:interceptors>


</beans>
  1. springmvc.xml【有缓存,SpringMVC配置文件】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">


<!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->
<context:component-scan base-package="cn.com.byte1024.controller" />



<!--避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>

<!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 -->
</list>
</property>
</bean>

<!-- 扩充了注解驱动,可以将请求参数绑定到控制器参数 -->
<mvc:annotation-driven/>

<!-- 开启静态资源处理 -->
<mvc:default-servlet-handler/>

<!-- 定义跳转的文件的前后缀 ,视图模式配置-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

<!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760000" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>

</beans>
  1. generatorConfig.xml【自动生成缓存配置文件,有redis】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动-->
<classPathEntry location="mysql-connector-java-5.1.23-bin.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/vote_system" userId="root" password="root">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置 实体类-->
<javaModelGenerator targetPackage="cn.com.byte1024.entity" targetProject=".././java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置 映射xml文件-->
<sqlMapGenerator targetPackage="cn.com.byte1024.mapper" targetProject=".././java">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="cn.com.byte1024.mapper" targetProject=".././java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<table tableName="user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="user_vote_project" domainObjectName="UserVoteProject" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="vote" domainObjectName="Vote" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="vote_log" domainObjectName="VoteLog" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="vote_project" domainObjectName="VoteProject" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="vote_project_vote" domainObjectName="VoteProjectVote" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<table tableName="register_log" domainObjectName="RegisterLog" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<!--<table tableName="tb_help" domainObjectName="Help" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
<table tableName="tb_admin" domainObjectName="Admin" selectByExampleQueryId="false" enableSelectByExample="false" enableDeleteByExample="false" enableUpdateByExample="false" enableCountByExample="false"></table>
<!-- 在这个目录下用cmd和这个命令生成实体类、dao、xml映射文件 -->
<!-- java -jar mybatis-generator-core-1.3.2.jar -configfile generatorConfig.xml -overwrite -->
</context>
</generatorConfiguration>
  1. web.xml【有redis】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!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 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>VoteSystem</display-name>
<!-- Spring和mybatis的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<!-- 编码过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

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

<!-- 防止Spring内存溢出监听器 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>

<!-- Spring MVC servlet -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>

<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
<url-pattern>/</url-pattern>
</servlet-mapping>

<welcome-file-list>
<!-- <welcome-file>/WEB-INF/jsp/login.jsp</welcome-file>-->
<welcome-file>/WEB-INF/jsp/front.jsp</welcome-file>
</welcome-file-list>
</web-app>

  1. web.xml【无缓存】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!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 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebAPP_id" version="3.1">
<display-name>Archetype Created Web Application</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<!-- 配置前端过滤器 -->
<servlet-name>springmvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 初始化时加载配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<!-- 表示容器在启动时立即加载Servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>


  1. entity【实体类】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package cn.com.byte1024.entity;

public class User {
private String userId;

private String loginName;

private String userName;

private String password;

private String phone;

private String email;

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId == null ? null : userId.trim();
}

public String getLoginName() {
return loginName;
}

public void setLoginName(String loginName) {
this.loginName = loginName == null ? null : loginName.trim();
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName == null ? null : userName.trim();
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password == null ? null : password.trim();
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone == null ? null : phone.trim();
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
}
  1. DAO【数据访问层】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package cn.com.byte1024.mapper;

import cn.com.byte1024.entity.User;
import org.apache.ibatis.annotations.Param;

public interface UserMapper {

User selectByUser(User user);

User selectByLoginName(@Param(value="phone") String phone);

int saveUser(User user);

User selectByPrimaryKey(String userId);

int updateByPrimaryKeySelective(User record);

int deleteByPrimaryKey(String userId);

int insert(User record);

int insertSelective(User record);

int updateByPrimaryKey(User record);

}
  1. Mapper【数据访问层映射文件】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.com.byte1024.mapper.UserMapper" >
<resultMap id="BaseResultMap" type="cn.com.byte1024.entity.User" >
<id column="user_id" property="userId" jdbcType="VARCHAR" />
<result column="login_name" property="loginName" jdbcType="VARCHAR" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<result column="phone" property="phone" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
user_id, login_name, user_name, password, phone, email
</sql>

<select id="selectByUser" resultMap="BaseResultMap" parameterType="cn.com.byte1024.entity.User">
select
<include refid="Base_Column_List" />
from user
where login_name=#{loginName,jdbcType=VARCHAR} and password=#{password,jdbcType=VARCHAR}
</select>

<select id="selectByLoginName" resultType="cn.com.byte1024.entity.User" parameterType="java.lang.String">
select
<include refid="Base_Column_List" />
from user
where login_name=#{phone} limit 1
</select>

<insert id="saveUser" parameterType="cn.com.byte1024.entity.User">
insert into
user(user_id,login_name,user_name,password,phone,email)
values(#{userId},#{loginName},#{userName},#{password},#{phone},#{email})
</insert>

<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from user
where user_id = #{userId,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
delete from user
where user_id = #{userId,jdbcType=VARCHAR}
</delete>
<insert id="insert" parameterType="cn.com.byte1024.entity.User" >
insert into user (user_id, login_name, user_name,
password, phone, email
)
values (#{userId,jdbcType=VARCHAR}, #{loginName,jdbcType=VARCHAR}, #{userName,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="cn.com.byte1024.entity.User" >
insert into user
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="userId != null" >
user_id,
</if>
<if test="loginName != null" >
login_name,
</if>
<if test="userName != null" >
user_name,
</if>
<if test="password != null" >
password,
</if>
<if test="phone != null" >
phone,
</if>
<if test="email != null" >
email,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="userId != null" >
#{userId,jdbcType=VARCHAR},
</if>
<if test="loginName != null" >
#{loginName,jdbcType=VARCHAR},
</if>
<if test="userName != null" >
#{userName,jdbcType=VARCHAR},
</if>
<if test="password != null" >
#{password,jdbcType=VARCHAR},
</if>
<if test="phone != null" >
#{phone,jdbcType=VARCHAR},
</if>
<if test="email != null" >
#{email,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="cn.com.byte1024.entity.User" >
update user
<set >
<if test="loginName != null" >
login_name = #{loginName,jdbcType=VARCHAR},
</if>
<if test="userName != null" >
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="password != null" >
password = #{password,jdbcType=VARCHAR},
</if>
<if test="phone != null" >
phone = #{phone,jdbcType=VARCHAR},
</if>
<if test="email != null" >
email = #{email,jdbcType=VARCHAR},
</if>
</set>
where user_id = #{userId,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="cn.com.byte1024.entity.User" >
update user
set login_name = #{loginName,jdbcType=VARCHAR},
user_name = #{userName,jdbcType=VARCHAR},
password = #{password,jdbcType=VARCHAR},
phone = #{phone,jdbcType=VARCHAR},
email = #{email,jdbcType=VARCHAR}
where user_id = #{userId,jdbcType=VARCHAR}
</update>
</mapper>
  1. service【业务逻辑层接口】
1
2
3
4
5
6
7
8
9
10
11
12
package cn.com.byte1024.service;

import cn.com.byte1024.entity.User;

public interface UserService {
User selectByUser(User user);

User selectByLoginName(String phone);

int saveUser(User user);
}

  1. service.impl【业务逻辑层实现类】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package cn.com.byte1024.service.impl;

import cn.com.byte1024.entity.User;
import cn.com.byte1024.mapper.UserMapper;
import cn.com.byte1024.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* @ProjectName: VoteSystem
* @ClassName: UserServiceImpl
* @Description:
* @Author: xxy
* @Date: 2021/4/4 2:13
*/
@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper;

@Override
public User selectByUser(User user) {
return userMapper.selectByUser(user);
}

@Override
public User selectByLoginName(String phone) {
return userMapper.selectByLoginName(phone);
}

@Override
public int saveUser(User user) {
return userMapper.saveUser(user);
}
}

  1. Controller【控制表现层】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package cn.com.byte1024.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* @ProjectName: VoteSystem
* @ClassName: LoginController
* @Description:
* @Author: xxy
* @Date: 2021/05/25 22:23
*/
@Controller
@RequestMapping("/login")
public class LoginController {

@RequestMapping("/goLoginJsp")
public String toLoginJsp(){
return "login";
}
@RequestMapping("/goAdminLoginJsp")
public String goAdminLoginJsp(){
return "adminlogin";
}
}

  1. 前端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit|ie-comp|ie-stand">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<!--[if lt IE 9]>
<script type="text/javascript" src="${pageContext.request.contextPath}/lib/html5shiv.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/lib/respond.min.js"></script>
<![endif]-->
<link href="${pageContext.request.contextPath}/static/h-ui/css/H-ui.min.css" rel="stylesheet" type="text/css" />
<link href="${pageContext.request.contextPath}/static/h-ui.admin/css/H-ui.login.css" rel="stylesheet" type="text/css" />
<link href="${pageContext.request.contextPath}/static/h-ui.admin/css/style.css" rel="stylesheet" type="text/css" />
<link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet">
<link href="${pageContext.request.contextPath}/lib/Hui-iconfont/1.0.8/iconfont.css" rel="stylesheet" type="text/css" />
<link href="${pageContext.request.contextPath}/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/font-awesome.min.css">
<link href="${pageContext.request.contextPath}/css/front.css" rel="stylesheet">
<!--[if IE 6]>
<script type="text/javascript" src="${pageContext.request.contextPath}/lib/DD_belatedPNG_0.0.8a-min.js" ></script>
<script>DD_belatedPNG.fix('*');</script>
<![endif]-->
<title>登录 - 投票管理系统</title>
</head>
<body>
<input type="hidden" id="" name="" value="" />

<!-- 导航栏开始 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExample08" aria-controls="navbarsExample08" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>

<div class="collapse navbar-collapse justify-content-md-center" id="navbarsExample08">
<ul class="navbar-nav">
<li class="nav-item">
<div class="nav-link">
<i class="fa fa-paper-plane-o fa-fw"></i>有你一票
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="${pageContext.request.contextPath}/front/goFrontJsp"><i class="fa fa-home fa-fw" aria-hidden="true"></i>首页</a>
</li>
<%-- <li class="nav-item">
<a class="nav-link" href="${pageContext.request.contextPath}/front/goClassifyJsp"><i class="fa fa-pie-chart fa-fw"></i>分类</a>
</li>--%>

<li class="nav-item">
<a class="nav-link" href="${pageContext.request.contextPath}/front/goHelpJsp"><i class="fa fa-heart fa-fw"></i>帮助</a>
</li>
<li class="nav-item">
<a class="nav-link" href="${pageContext.request.contextPath}/front/goAboutJsp"><i class="fa fa-envelope fa-fw"></i>关于</a>
</li>
<li class="nav-item">
<a class="nav-link" href="${pageContext.request.contextPath}/front/goFeedbackAddJsp"><i class="fa fa-undo fa-fw"></i>反馈</a>
</li>
<li class="nav-item">
<a class="nav-link btn btn-outline-success" href="${pageContext.request.contextPath}/register/goRegisterJsp"><i class="fa fa-user fa-fw"></i>注册</a>
</li>
</ul>
</div>
</nav>
<!-- 导航栏结束 -->

<div class="loginWraper" <%--style="background: url('${pageContext.request.contextPath}/static/h-ui.admin/images/liti2.jpg')"--%>>

<div id="loginform" class="loginBox" style="height: 400px">

<div class="lg-title">
<h3><i class="fa fa-paper-plane-o fa-fw"></i>有你一票</h3>
<span style="color: red;">${msg }</span>
</div>

<form class="form form-horizontal" id="loginForm1" action="${pageContext.request.contextPath}/user/login" method="post">

<div class="row cl">
<label class="form-label col-xs-3"><i class="Hui-iconfont">&#xe60d;</i></label>
<div class="formControls col-xs-8">
<input id="loginName" name="loginName" type="text" placeholder="请输入账户" class="input-text size-L" required="required">
</div>
</div>
<br>
<div class="row cl">
<label class="form-label col-xs-3"><i class="Hui-iconfont">&#xe60e;</i></label>
<div class="formControls col-xs-8">
<input id="password" name="password" type="password" placeholder="请输入密码" class="input-text size-L" required="required">
</div>
</div>

<%-- <div class="row cl">
<div class="formControls col-xs-8 col-xs-offset-3">
<label for="online">
<input type="checkbox" name="online" id="online" value="">
记住密码</label>
</div>
</div>--%>
<div class="row cl">
<div class="formControls col-xs-8 col-xs-offset-3">
<input name="" type="submit" class="btn btn-success radius size-L" value="&nbsp;登&nbsp;&nbsp;&nbsp;&nbsp;录&nbsp;">&nbsp;&nbsp;
<input name="" type="reset" class="btn btn-default radius size-L" value="&nbsp;重&nbsp;&nbsp;&nbsp;&nbsp;置&nbsp;">
</div>
</div>
<%-- <div class="row cl">
<div class="formControls col-xs-8 col-xs-offset-3">
<a href="${pageContext.request.contextPath}/register/goRegisterJsp" style="">还没有账号?免费注册</a>
</div>
</div>--%>
<div style="font-size:14px;color:red;width:180px;height:15px;padding:15px 0px 0px 45px;overflow:hidden;" id="msg">${msg}</div>
</form>
</div>
</div>
<div class="footer"><i class="fa fa-paper-plane-o fa-fw"></i>Copyright © 2021 玄宇有限公司 投票管理系统v1.0. All Rights Reserved.</div>
<script type="text/javascript" src="${pageContext.request.contextPath}/lib/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/h-ui/js/H-ui.min.js"></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.bundle.min.js"></script>
<script type="text/javascript">

</script>
</body>
</html>

15. 总结

总结了JavaSSM企业框架,明白要做的事情还有很多,要走的路还有很长,时间很短,却要做很多来不及的事情,随心出发最好。