ssm框架大整合
Ioc
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
HelloSpring
导入jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
//1、编写一个Hello实体类
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("Hello,"+ name );
}
}
编写spring配置文件
测试
思考
-
Hello 对象是谁创建的 ? 【hello 对象是由Spring创建的
-
Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的
这个过程就叫控制反转 :
-
控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
-
反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .
IOC创建对象方式
1、通过无参构造方法来创建
public class User {
private String name;
public User() {
System.out.println("user无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
bean.xml
2、通过有参构造方法来创建
public class UserT {
private String name;
public UserT(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
bean.xml <!-- 第一种根据index参数下标设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <!-- index指构造方法 , 下标从0开始 --> <constructor-arg index="0" value="kuangshen2"/> </bean> <!-- 第二种根据参数名字设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <!-- name指参数名 --> <constructor-arg name="name" value="kuangshen2"/> </bean> <!-- 第三种根据参数类型设置 --> <bean id="userT" class="com.kuang.pojo.UserT"> <constructor-arg type="java.lang.String" value="kuangshen2"/> </bean>
依赖注入
set注入
要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .
Address.java
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Student.java
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
public void setName(String name) {
this.name = name;
}
public void setAddress(Address address) {
this.address = address;
}
public void setBooks(String[] books) {
this.books = books;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public void setGames(Set<String> games) {
this.games = games;
}
public void setWife(String wife) {
this.wife = wife;
}
public void setInfo(Properties info) {
this.info = info;
}
public void show(){
System.out.println("name="+ name
+ ",address="+ address.getAddress()
+ ",books="
);
for (String book:books){
System.out.print("<<"+book+">>\t");
}
System.out.println("\n爱好:"+hobbys);
System.out.println("card:"+card);
System.out.println("games:"+games);
System.out.println("wife:"+wife);
System.out.println("info:"+info);
}
}
1、常量注入
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
</bean>
2、Bean注入
<bean id="addr" class="com.kuang.pojo.Address">
<property name="address" value="重庆"/>
</bean>
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
</bean>
3、数组注入
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
</bean>
4、List注入
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>爬山</value>
</list>
</property>
5、Map注入
<property name="card">
<map>
<entry key="中国邮政" value="456456456465456"/>
<entry key="建设" value="1456682255511"/>
</map>
</property>
6、set注入
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>
7、Null注入
<property name="wife"><null/></property>
8、Properties注入
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="性别">男</prop>
<prop key="姓名">小明</prop>
</props>
</property>
p命名和c命名注入
User.java
public class User {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
1、P命名空间注入 : 需要在头文件中加入约束文件
导入约束 : xmlns:p="http://www.springframework.org/schema/p" <!--P(属性: properties)命名空间 , 属性依然要设置set方法--> <bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
2、c 命名空间注入 : 需要在头文件中加入约束文件
导入约束 : xmlns:c="http://www.springframework.org/schema/c" <!--C(构造: Constructor)命名空间 , 属性依然要设置set方法--> <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>
发现问题:爆红了,刚才我们没有写有参构造!
解决:把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!
自动装配
自动装配说明
-
自动装配是使用spring满足bean依赖的一种方法
-
spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制,分别是:
-
在xml中显式配置;
-
在java中显式配置;
-
隐式的bean发现机制和自动装配。
这里我们主要讲第三种:自动化的装配bean。
Spring的自动装配需要从两个角度来实现,或者说是两个操作:
-
组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
-
自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。
推荐不使用自动装配xml配置 , 而使用注解 .
1、新建一个项目
2、新建两个实体类,Cat Dog 都有一个叫的方法
public class Cat {
public void shout() {
System.out.println("miao~");
}
}
public class Dog {
public void shout() {
System.out.println("wang~");
}
}
public class User {
private Cat cat;
private Dog dog;
private String str;
}
<?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.xsd">
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="str" value="qinjiang"/>
</bean>
</beans>
public class MyTest {
@Test
public void testMethodAutowire() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.getCat().shout();
user.getDog().shout();
}
}
结果正常输出,环境OK
byName
autowire byName (按名称自动装配)
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。
采用自动装配将避免这些错误,并且使配置简单化。
测试:
1、修改bean配置,增加一个属性 autowire="byName"
<bean id="user" class="com.kuang.pojo.User" autowire="byName"> <property name="str" value="qinjiang"/> </bean>
2、再次测试,结果依旧成功输出!
3、我们将 cat 的bean id修改为 catXXX
4、再次测试, 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。
小结:
当一个bean节点带有 autowire byName的属性时。
-
将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
-
去spring容器中寻找是否有此字符串名称id的对象。
-
如果有,就取出注入;如果没有,就报空指针异常。
byType
autowire byType (按类型自动装配)
使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
NoUniqueBeanDefinitionException
测试:
1、将user的bean配置修改一下 : autowire="byType"
2、测试,正常输出
3、在注册一个cat 的bean对象!
<bean id="dog" class="com.kuang.pojo.Dog"/> <bean id="cat" class="com.kuang.pojo.Cat"/> <bean id="cat2" class="com.kuang.pojo.Cat"/> <bean id="user" class="com.kuang.pojo.User" autowire="byType"> <property name="str" value="qinjiang"/> </bean>
4、测试,报错:NoUniqueBeanDefinitionException
5、删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。
这就是按照类型自动装配!
使用注解
使用注解
jdk1.5开始支持注解,spring2.5开始全面支持注解。
准备工作:利用注解的方式注入属性。
1、在spring配置文件中引入context文件头
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
2、开启属性注解支持!
<context:annotation-config/>
@Autowired
-
@Autowired是按类型自动转配的,不支持id匹配。
-
需要导入 spring-aop的包!
测试:
1、将User类中的set方法去掉,使用@Autowired注解
public class User {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String str;
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getStr() {
return str;
}
}
2、此时配置文件内容
<context:annotation-config/> <bean id="dog" class="com.kuang.pojo.Dog"/> <bean id="cat" class="com.kuang.pojo.Cat"/> <bean id="user" class="com.kuang.pojo.User"/>
3、测试,成功输出结果!
@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。
//如果允许对象为null,设置required = false,默认为true @Autowired(required = false) private Cat cat;
@Qualifier
-
@Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
-
@Qualifier不能单独使用。
测试实验步骤:
1、配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!
<bean id="dog1" class="com.kuang.pojo.Dog"/> <bean id="dog2" class="com.kuang.pojo.Dog"/> <bean id="cat1" class="com.kuang.pojo.Cat"/> <bean id="cat2" class="com.kuang.pojo.Cat"/>
2、没有加Qualifier测试,直接报错
3、在属性上添加Qualifier注解
@Autowired @Qualifier(value = "cat2") private Cat cat; @Autowired @Qualifier(value = "dog2") private Dog dog;
@Resource
-
@Resource如有指定的name属性,先按该属性进行byName方式查找装配;
-
其次再进行默认的byName方式进行装配;
-
如果以上都不成功,则按byType的方式自动装配。
-
都不成功,则报异常。
实体类:
public class User {
//如果允许对象为null,设置required = false,默认为true
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
private String str;
}
<bean id="dog" class="com.kuang.pojo.Dog"/> <bean id="cat1" class="com.kuang.pojo.Cat"/> <bean id="cat2" class="com.kuang.pojo.Cat"/> <bean id="user" class="com.kuang.pojo.User"/>
测试:结果OK
配置文件2:beans.xml , 删掉cat2
<bean id="dog" class="com.kuang.pojo.Dog"/> <bean id="cat1" class="com.kuang.pojo.Cat"/>
实体类上只保留注解
@Resource private Cat cat; @Resource private Dog dog;
结果:OK
结论:先进行byName查找,失败;再进行byType查找,成功。
小结
@Autowired与@Resource异同:
1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。
使用注解开发
在spring4之后,想要使用注解形式,必须得要引入aop的包
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
Bean的实现
我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!
1、配置扫描哪些包下的注解
<!--指定注解扫描包--> <context:component-scan base-package="com.kuang.pojo"/>
2、在指定包下编写类,增加注解
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
public String name = "秦疆";
}
属性注入
使用注解注入属性
1、可以不用提供set方法,直接在直接名上添加@value("值")
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
@Value("秦疆")
// 相当于配置文件中 <property name="name" value="秦疆"/>
public String name;
}
2、如果提供了set方法,在set方法上添加@value("值");
@Component("user")
public class User {
public String name;
@Value("秦疆")
public void setName(String name) {
this.name = name;
}
}
衍生注解
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
-
@Controller:web层
-
@Service:service层
-
@Repository:dao层
写上这些注解,就相当于将这个类交给Spring管理装配了!
自动装配注解
在Bean的自动装配已经讲过了,可以回顾!
作用域
@scope
-
singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
-
prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
@Controller("user")
@Scope("prototype")
public class User {
@Value("秦疆")
public String name;
}
小结
XML与注解比较
-
XML可以适用任何场景 ,结构清晰,维护方便
-
注解不是自己提供的类使用不了,开发简单方便
xml与注解整合开发 :推荐最佳实践
-
xml管理Bean
-
注解完成属性注入
-
使用过程中, 可以不用扫描,扫描是为了类上的注解
<context:annotation-config/>
作用:
-
进行注解驱动注册,从而使注解生效
-
用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
-
如果不扫描包,就需要手动配置bean
-
如果不加注解驱动,则注入的值为null!
aop
AOP:面向切面、面向方面、面向接口是一种横切技术 横切技术运用: 1.事务管理: (1)数据库事务:(2)编程事务(3)声明事物:Spring AOP-->声明事物 2.日志处理: 3.安全验证: Spring AOP---OOP升级
静态代理原理:目标对象:调用业务逻辑 代理对象:日志管理 表示层调用--->代理对象(日志管理)-->调用目标对象
动态代理原理:spring AOP采用动态代理来实现 (1)实现InvocationHandler接口
(2)创建代理类(通过java API)
Proxy.newProxyInstance(动态加载代理类,代理类实现接口,使用handler);
(3)调用invoke方法(虚拟机自动调用方法)
日志处理 //调用目标对象 method.invoke("目标对象","参数"); 日志处理
通过代理对象--(请求信息)-->目标对象---(返回信息)----> 代理对象
Spring 动态代理中的基本概念
1、关注点(concern) 一个关注点可以是一个特定的问题,概念、或者应用程序的兴趣点。总而言之,应用程序必须达到一个目标 安全验证、日志记录、事务管理都是一个关注点 在oo应用程序中,关注点可能已经被代码模块化了还可能散落在整个对象模型中 2、横切关注点(crosscutting concern) 如何一个关注点的实现代码散落在多个类中或方法中 3、方面(aspect) 一个方面是对一个横切关注点模块化,它将那些原本散落在各处的, 用于实现这个关注点的代码规整在一处 4、建议(advice)通知 advice是point cut执行代码,是方面执行的具体实现 5、切入点(pointcut) 用于指定某个建议用到何处 6、织入(weaving) 将aspect(方面)运用到目标对象的过程 7、连接点(join point) 程序执行过程中的一个点
通知类型: try{ //前置通知 //环绕通知 //调用目标对象方法 //环绕通知 //后置通知 }catch(){ //异常通知 }finally{ //终止通知 }
一.静态代理原理实例:
IUserServ接口代码
public interface IUserServ {
List<User> findAllUser();
int deleteUserById(User user);
int saveUser(User user);
}
UserServImpl实现类代码
public class UserServImpl implements IUserServ {
public int deleteUserById(User user) {
System.out.println("******执行删除方法******");
return 0;
}
public List<User> findAllUser() {
System.out.println("*******执行查询方法*******");
return null;
}
public int saveUser(User user) {
System.out.println("*******执行添加方法********");
return 0;
}
}
UserServProxyImpl实现类代码
//代理类:完成日志输出
public class UserServProxyImpl implements IUserServ {
// 访问目标对象(UserServImpl)
// 代理对象(UserServProxyImpl)
// 创建目标对象
private IUserServ iuserServ ;//= new UserServImpl();
public UserServProxyImpl(IUserServ iuserServ){
this.iuserServ = iuserServ;
}
public int deleteUserById(User user) {
beforeLog();
//调用目标对象里方法
iuserServ.deleteUserById(user);
afterLog();
return 0;
}
public List<User> findAllUser() {
beforeLog();
//调用目标对象里方法
iuserServ.findAllUser();
afterLog();
return null;
}
public int saveUser(User user) {
beforeLog();
//调用目标对象里方法
iuserServ.saveUser(user);
afterLog();
return 0;
}
private void beforeLog() {
System.out.println("开始执行");
}
private void afterLog() {
System.out.println("执行完毕");
}
}
ActionTest测试类代码
public class ActionTest {
public static void main(String[] args) {
//用户访问代理对象---信息->目标对象
IUserServ iuserServ = new UserServProxyImpl(new UserServImpl());
iuserServ.findAllUser();
}
}
运行结果:
开始执行 ***执行查询方法*** 执行完毕
二.动态代理实例
IUserServ接口代码与UserServImpl实现类代码和上述代码相同
LogHandler类代码
public class LogHandler implements InvocationHandler {
//目标对象
private Object targetObject;
/**
* 创建动态代理类
* @return object(代理类)
*/
public Object createProxy(Object targetObject){
this.targetObject = targetObject;
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj = null;
try {
beforeLog();
//obj: 目标对象--->代理对象的返回值--->返回给调用者的信息
//this.invoke("目标对象","代理对象给目标对象传递参数");
//调用目标对象中方法
obj = method.invoke(targetObject, args);
afterLog();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
//日志管理方法
private void beforeLog(){
System.out.println("开始执行");
}
private void afterLog(){
System.out.println("执行完毕");
}
}
ActionTest测试类代码:
public class ActionTest {
public static void main(String[] args) {
//创建代理对象iuserServ
LogHandler handler = new LogHandler();
IUserServ iuserServ = (IUserServ)handler.createProxy(new UserServImpl());
iuserServ.deleteUserById(new User());
}
}
运行结果: 开始执行 **执行删除方法** 执行完毕
三.Spring AOP(方式一)
2.x版本之前
IUserServ接口代码与UserServImpl实现类代码和上述代码相同
1、配置目标对象(applicationContext.xml)
<bean id="userServTarget" class="com.tarena.biz.impl.UserServImpl"/>
2、配置通知 (a)前置通知(BeforeLogAdvice)
public class BeforeLogAdvice implements MethodBeforeAdvice {
/**
* Method method:调用目标对象的方法
* Object[] args:发送给目标对象的参数列表
* Object target:目标对象
*/
public void before(Method method, Object[] args, Object target)
throws Throwable {
beforeLog();
}
private void beforeLog(){
System.out.println("开始执行");
}
}
(b)后置通知(AfterLogAdvice)
public class AfterLogAdvice implements AfterReturningAdvice {
/**
* Object returnValue:目标对象返回值
* Method method:目标对象方法名
* Object[] args:目标对象参数列表
* Object target:目标对象
*/
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
afterLog();
}
private void afterLog(){
System.out.println("执行完毕");
}
}
(c)在spring容器中,让容器管理通知(applicationContext.xml)
<!-- 定义通知 -->
<!-- 前置通知 -->
<bean id="beforeLogAdvice" class="com.tarena.advice.BeforeLogAdvice"/>
<!-- 后置通知 -->
<bean id="afterLogAdvice" class="com.tarena.advice.AfterLogAdvice"/>
3、配置代理对象(applicationContext.xml)
<!-- 代理类作用: 生成代理类,织入通知 -->
<bean id="userServProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces">
<!-- 可以添加多个接口 -->
<list>
<value>com.tarena.biz.IUserServ</value>
</list>
</property>
<!-- 引入通知 -->
<property name="interceptorNames">
<list>
<value>beforeLogAdvice</value>
<value>afterLogAdvice</value>
</list>
</property>
<!-- 目标对象 -->
<property name="target" ref="userServTarget"/>
</bean>
4.访问() Spring容器:通过代理对象调用-->织入通知--->目标对象 程序员:访问代理对象
测试类(ActionTest):
public class ActionTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
IUserServ iuserServ = (IUserServ)ac.getBean("userServProxy");
iuserServ.deleteUserById(new User());
iuserServ.findAllUser();
}
}
运行结果:
开始执行 **执行删除方法** 执行完毕 开始执行 ***执行查询方法*** 执行完毕
四.Spring AOP(方式二)
2.x版本之后
这种方式需要额外添加两个jar包,
存放位置在spring-framework-2.5.6.SEC01\lib\aspectj文件夹下。
IUserServ接口代码与UserServImpl实现类代码和上述代码相同
LogAdvice中
public class LogAdvice {
public void beforeLog(){
System.out.println("开始执行");
}
public void afterLog(){
System.out.println("执行完毕");
}
}
applicationContext.xml中
<!-- spring2.x后 -->
<!-- 目标对象 -->
<bean id="userServImpl" class="com.tarena.biz.impl.UserServImpl"/>
<!-- 通知 -->
<bean id="logAdvice" class="com.tarena.advice.LogAdvice"/>
<aop:config>
<aop:aspect id="logAspect" ref="logAdvice">
<!-- 切入点 -->
<aop:pointcut id="beforePointCut"
expression="execution(* saveUser*(..))"/>
<aop:pointcut id="afterPointCut"
expression="execution(* saveUser*(..))"/>
<!-- 织入(通知作用于切入点) -->
<aop:before method="beforeLog" pointcut-ref="beforePointCut"/>
<aop:after method="afterLog" pointcut-ref="afterPointCut"/>
</aop:aspect>
</aop:config>
测试类:
public class ActionTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
IUserServ iuserServ = (IUserServ)ac.getBean("userServImpl");
iuserServ.deleteUserById(new User());
iuserServ.findAllUser();
iuserServ.saveUser(new User());
}
}
运行结果 **执行删除方法** ***执行查询方法*** 开始执行 ***执行添加方法**** 执行完毕
注:如果要在业务层所有的方法前后添加日志文件,则需要更改为以下配置
<aop:pointcut id="beforePointCut"
expression="execution(* com.tarena.biz.*.*(..))"/>
<aop:pointcut id="afterPointCut"
expression="execution(* com.tarena.biz.*.*(..))"/>
运行结果:
开始执行 **执行删除方法** 执行完毕 开始执行 ***执行查询方法*** 执行完毕 开始执行 ***执行添加方法**** 执行完毕
五.环绕通知
包含前置、后置等等
示例代码:
日志类:
import org.aspectj.lang.ProceedingJoinPoint;
public class Logger {
//前置通知
public void beforePrintLog(){
System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志");
}
//后置通知
public void afterReturnPrintLog(){
System.out.println("后置通知Logger类中的afterReturnPrintLog方法开始记录日志");
}
//异常通知
public void afterThrowingPrintLog(){
System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志");
}
//最终通知
public void afterPrintLog(){
System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志");
}
/*
* 环绕通知:
* 配置环绕通知之后,切入点方法没有执行,但是通知方法执行了
* 解决:
* Spring框架为我们提供了一个接口:ProceedingJoinPoint
* 该接口中提供了一个方法procceed(),此方法就相当于明确调用切入点方法
* 该接口可以作为环绕通知接口的参数,在程序执行时,
* 在Spring程序执行时,Spring框架会为我们提供该接口的实现类供我么使用
*/
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object result = null;
try {
Object[] args = pjp.getArgs();//得到方法执行的返回参数
System.out.println("Logger类中的aroundPrintLog方法开始记录日志...前置");
pjp.proceed(args);//明确调用业务层方法
System.out.println("Logger类中的aroundPrintLog方法开始记录日志...后置");
return result;
} catch (Throwable throwable) {
System.out.println("Logger类中的aroundPrintLog方法开始记录日志...异常");
throw new RuntimeException(throwable);
}finally {
System.out.println("Logger类中的aroundPrintLog方法开始记录日志...最终");
}
}
}
配置
<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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置Spring的IOC-->
<bean id="accountService" class="com.hh.service.AccountServiceImpl"/>
<bean id="logger" class="com.hh.utils.Logger"/>
<!--配置AOP-->
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<!--配置环绕通知-->
<aop:around method="aroundPrintLog" pointcut-ref="pt"/>
<aop:pointcut id="pt" expression="execution(* com.hh.service.*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
六.注解实现
xml
开启aop注解支持 <aop:aspectj-autoproxy/>
具体实现
@Component
@Aspect //切面注解
public class Logger {
@Before(value = "execution(* com.jun.service.*.*(..))")
public void beforeLog(JoinPoint joinPoint){
System.out.println("前置通知"+joinPoint.getSignature().getName());
}
@After(value = "execution(* com.jun.service.*.*(..))")
public void afterLog(JoinPoint joinPoint){
System.out.println("后置通知通知"+joinPoint.getSignature().getName());
}
}
JdbcTemplate事务
基本概念
什么是事务
-
事务就是将一组SQL语句放在同一批次内去执行
-
如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行
-
MySQL事务处理只支持InnoDB和BDB数据表类型
事务的ACID原则 百度 ACID
原子性(Atomic)
-
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(ROLLBACK)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Consist)
-
一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。
隔离性(Isolated)
-
隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
持久性(Durable)
-
在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
jdbc基本使用
xml注入配置
<!-- 加载数据库配置文件-->
<context:property-placeholder location="classpath:db.properties"/>
<!--开启包扫描-->
<context:component-scan base-package="com"/>
<!-- 配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置spring_jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
dao层代码示例
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void moneyOut(Integer code, Float money) {
String sql="update account set money=money-? where code=?";
jdbcTemplate.update(sql,money,code);
}
@Override
public void moneyIn(Integer code, Float money) {
String sql="update account set money=money+? where code=?";
jdbcTemplate.update(sql,money,code);
}
}
事务处理示例
1、编程式处理(不推荐使用----繁琐)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
//配置事务管理器
private DataSourceTransactionManager manager;
public void setManager(DataSourceTransactionManager manager) {
this.manager = manager;
}
public DataSourceTransactionManager getManager() {
return manager;
}
//set方法注入
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(Integer outCode, Integer inCode, float money) {
TransactionStatus transaction = null;
try {
//定义事务状态
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
//设置传播行为
definition.setPropagationBehavior(3);
//获取事务状态
transaction=manager.getTransaction(definition);
accountDao.moneyOut(outCode, money);
int a=10/0;
accountDao.moneyIn(inCode, money);
manager.commit(transaction);
} catch (Exception e) {
System.out.println("异常回滚");
manager.rollback(transaction);
}
}
}
xml配置
<!-- 配置spring_jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 注入持久层-->
<bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!-- 注入业务层-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="manager" ref="manger"/>
</bean>
<!-- 创建事务管理器-->
<bean id="manger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
2、声明式事务管理
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
//set方法注入
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(Integer outCode, Integer inCode, float money) {
accountDao.moneyOut(outCode, money);
int a = 10 / 0;
accountDao.moneyIn(inCode, money);
}
}
xml声明式配置
<!-- 配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置spring_jdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--注入持久层-->
<bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--注入业务层-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--创建、配置事务管理器-->
<bean id="manger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务属性 配置通知 引入事务,命名空间-->
<tx:advice id="txAdvice" transaction-manager="manger">
<tx:attributes>
<!--配置属性名 即使需要事务的方法名 例如find* 就是find开头的方法 * 就是全部方法-->
<!-- REQUIRED是默认的-->
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切入点 aop实现-->
<aop:config>
<!-- 配置切入点表达式-->
<aop:pointcut id="txPointCut" expression="execution(* com.service.impl.AccountServiceImpl.*(..))"/>
<!-- 配置通知-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
两种方式的优缺点:
编程式事务管理
-
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
-
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
-
一般情况下比编程式事务好用。
-
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
-
将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
spring事务传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
-
propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
-
propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
-
propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
-
propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
-
propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
-
propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
-
propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。
假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。
就好比,我们刚才的几个方法存在调用,所以会被放在一组事务当中!
二、Spring-MVC
1、回顾MVC
1.1、什么是MVC
-
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
-
是将业务逻辑、数据、显示分离的方法来组织代码。
-
MVC主要作用是降低了视图与业务逻辑间的双向偶合。
-
MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
最典型的MVC就是JSP + servlet + javabean的模式。
1.2、Model1时代
-
在web早期的开发中,通常采用的都是Model1。
-
Model1中,主要分为两层,视图层和模型层。
-
Model1优点:架构简单,比较适合小型项目开发;
Model1缺点:JSP职责不单一,职责过重,不便于维护;
1.3、Model2时代
Model2把一个项目分成三部分,包括视图、控制、模型。
-
用户发请求
-
Servlet接收请求数据,并调用对应的业务逻辑方法
-
业务处理完毕,返回更新后的数据给servlet
-
servlet转向到JSP,由JSP来渲染页面
-
响应给前端更新后的页面
职责分析:
Controller:控制器
-
取得表单数据
-
调用业务逻辑
-
转向指定的页面
Model:模型
-
业务逻辑
-
保存数据的状态
View:视图
-
显示页面
Model2这样不仅提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本。Model 1模式的实现比较简单,适用于快速开发小规模项目,Model1中JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。Model2消除了Model1的缺点。
-
MVC框架要做哪些事情
-
将url映射到java类或java类的方法 .
-
封装用户提交的数据 .
-
处理请求--调用相关的业务处理--封装响应数据 .
-
将响应的数据进行渲染 . jsp / html 等表示层数据 .
说明:
常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常见前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等....
2、什么是SpringMVC
2.1、概述
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。
查看官方文档:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web
我们为什么要学习SpringMVC呢?
Spring MVC的特点:
-
轻量级,简单易学
-
高效 , 基于请求响应的MVC框架
-
与Spring兼容性好,无缝结合
-
约定优于配置
-
功能强大:RESTful、数据验证、格式化、本地化、主题等
-
简洁灵活
Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。
DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;
正因为SpringMVC好 , 简单 , 便捷 , 易学 , 天生和Spring无缝集成(使用SpringIoC和Aop) , 使用约定优于配置 . 能够进行简单的junit测试 . 支持Restful风格 .异常处理 , 本地化 , 国际化 , 数据验证 , 类型转换 , 拦截器 等等......所以我们要学习 .
最重要的一点还是用的人多 , 使用的公司多 .
2.2、中心控制器
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。
Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。
SpringMVC的原理如下图所示:
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
2.3、SpringMVC执行原理
图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。
简要分析执行流程
-
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
如上url拆分成三部分:
SpringMVC部署在服务器上的web站点
hello表示控制器
通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
-
HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
-
HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
-
HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
-
HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
-
Handler让具体的Controller执行。
-
Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
-
HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
-
DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
-
视图解析器将解析的逻辑视图名传给DispatcherServlet。
-
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
-
最终视图呈现给用户。
第一个MVC程序
配置版
1、新建一个Moudle , springmvc-02-hello , 添加web的支持!
2、确定导入了SpringMVC 的依赖!
3、配置web.xml , 注册DispatcherServlet
<?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">
<!--1.注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别-1-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4、编写SpringMVC 的 配置文件!名称:springmvc-servlet.xml : [servletname]-servlet.xml
说明,这里的名称要求是按照官方来的
<?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.xsd">
</beans>
5、添加 处理映射器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
6、添加 处理器适配器
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
7、添加 视图解析器
<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
8、编写我们要操作业务Controller ,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图;
//注意:这里我们先导入Controller接口
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放在ModelAndView中。Model
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}
9、将自己的类交给SpringIOC容器,注册bean
<!--Handler--><bean id="/hello" class="com.kuang.controller.HelloController"/>
10、写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Kuangshen</title>
</head>
<body>
${msg}
</body>
</html>
11、配置Tomcat 启动测试!
注解版
1、新建一个Moudle,springmvc-03-hello-annotation 。添加web支持!
2、由于Maven可能存在资源过滤的问题,我们将配置完善
<build>
<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>
3、在pom.xml文件引入相关的依赖:主要有Spring框架核心库、Spring MVC、servlet , JSTL等。我们在父依赖中已经引入了!
4、配置web.xml
注意点:
<?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">
<!--1.注册servlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
/ 和 /* 的区别:< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。< url-pattern > /* </ url-pattern > 会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
-
-
注意web.xml版本问题,要最新版!
-
注册DispatcherServlet
-
关联SpringMVC的配置文件
-
启动级别为1
-
映射路径为 / 【不要用/*,会404】
-
-
5、添加Spring MVC配置文件
-
在resource目录下添加springmvc-servlet.xml配置文件,配置的形式与Spring容器配置基本类似,为了支持基于注解的IOC,设置了自动扫描包的功能,具体配置信息如下:
-
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --> <context:component-scan base-package="com.kuang.controller"/> <!-- 让Spring MVC不处理静态资源 --> <mvc:default-servlet-handler /> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系 要想使@RequestMapping注解生效 必须向上下文中注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理。 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 --> <mvc:annotation-driven /> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans> -
在视图解析器中我们把所有的视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问。
-
-
让IOC的注解生效
-
静态资源过滤 :HTML . JS . CSS . 图片 , 视频 .....
-
MVC的注解驱动
-
配置视图解析器
-
-
-
6、创建Controller
-
编写一个Java控制类:com.kuang.controller.HelloController , 注意编码规范
-
package com.kuang.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/HelloController") public class HelloController { //真实访问地址 : 项目名/HelloController/hello @RequestMapping("/hello") public String sayHello(Model model){ //向模型中添加属性msg与值,可以在JSP页面中取出并渲染 model.addAttribute("msg","hello,SpringMVC"); //web-inf/jsp/hello.jsp return "hello"; } } -
-
@Controller是为了让Spring IOC容器初始化时自动扫描到;
-
@RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/HelloController/hello;
-
方法中声明Model类型的参数是为了把Action中的数据带到视图中;
-
方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp。
-
-
7、创建视图层
-
在WEB-INF/ jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息;
-
可以通过EL表示取出Model中存放的值,或者对象;
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>SpringMVC</title> </head> <body> ${msg} </body> </html> -
小结
-
实现步骤其实非常的简单:
-
新建一个web项目
-
导入相关jar包
-
编写web.xml , 注册DispatcherServlet
-
编写springmvc配置文件
-
接下来就是去创建对应的控制类 , controller
-
最后完善前端视图和controller之间的对应
-
测试运行调试.
-
-
使用springMVC必须配置的三大件:
-
处理器映射器、处理器适配器、视图解析器
-
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
RestFul 风格
概念
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,post 和 get
http://127.0.0.1/item/queryItem.action?id=1 查询,GET
http://127.0.0.1/item/saveItem.action 新增,POST
http://127.0.0.1/item/updateItem.action 更新,POST
http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可以不同!
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
学习测试
-
在新建一个类 RestFulController
@Controller public class RestFulController { } -
在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量上。
@Controller public class RestFulController { //映射访问路径 @RequestMapping("/commit/{p1}/{p2}") public String index(@PathVariable int p1, @PathVariable int p2, Model model){ int result = p1+p2; //Spring MVC会自动实例化一个Model对象用于向视图中传值 model.addAttribute("msg", "结果:"+result); //返回视图位置 return "test"; } }
三、mybatis
配置第一个mybatis
mybatis-config.xml 核心配置文件
<?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"/>
<!-- 设置日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
<!--开启驼峰命名法-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 别名-->
<typeAliases>
<typeAlias type="com.jun.pojo.Figure" alias="Figure"></typeAlias>
<typeAlias type="com.jun.pojo.Camp" alias="Camp"></typeAlias>
<typeAlias type="com.jun.pojo.Pro" alias="Pro"></typeAlias>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/jun/mapper/UserMapper.xml"/>
<mapper resource="com/jun/mapper/FigureMapper.xml"/>
</mappers>
</configuration>
xml映射文件 ****.xml
<?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.BooksMapper">
<select id="queryAllBooks" resultType="domain.Books">
select * from book
</select>
</mapper>
数据库相关信息 database.properties driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/book?serverTimezone=UTC username=root password=1234
测试运行 java
String resource="mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession=sqlSessionFactory.openSession;
XXXMapper mapper=sqlSession.getMapper(XXXMapper.class);
mapper.xxx;
可能遇到的问题资源过滤maven
<build>
<resources>
<resource>
<!-- 描述存放资源的目录,该路径相对POM路径-->
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
日志设置
导包log4j
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
配置文件 resources/log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
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=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
设置启用
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
mybatis一对多和多对一处理
多对一的处理:
按查询嵌套处理
<?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.jun.mapper.StudentMapper">
<!--
需求:获取所有学生及对应老师的信息
思路:
1. 获取所有学生的信息
2. 根据获取的学生信息的老师ID->获取该老师的信息
3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般使用关联查询?
1. 做一个结果集映射:StudentTeacher
2. StudentTeacher结果集的类型为 Student
3. 学生中老师的属性为teacher,对应数据库中为tid。
多个 [1,...)学生关联一个老师=> 一对一,一对多
4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查询
-->
<select id="getStudents" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
如果属性名和数据库字段名一致 此处的属性映射可以省略
只进行 关联 的映射操作 如下
<!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
column="{key=value,key=value}"
其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
-->
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
</mapper>
按结果嵌套处理
<!--
按查询结果嵌套处理
思路:
1. 直接查询出结果,进行结果集的映射
-->
<select id="getStudents2" resultMap="StudentTeacher2" >
select s.id sid, s.name sname , t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
映射属性
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<!--关联对象property 关联对象在Student实体类中的属性-->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
一对多的处理
按查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{id}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<!--column是一对多的外键 , 写的是一的主键的列名-->
<collection property="students" javaType="ArrayList" ofType="Student" column="id" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from student where tid = #{id}
</select>
按结果嵌套处理
<mapper namespace="com.kuang.mapper.TeacherMapper">
<!--
思路:
1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
2. 对查询出来的操作做结果集映射
1. 集合的话,使用collection!
JavaType和ofType都是用来指定对象类型的
JavaType是用来指定pojo中属性的类型
ofType指定的是映射到list集合属性中pojo的类型。
-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname , t.name tname, t.id tid
from student s,teacher t
where s.tid = t.id and t.id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
</mapper>
四、SSM整合
环境搭建
1、新建一Maven项目!ssmbuild , 添加web的支持
2、导入相关的pom依赖!
<dependencies>
<!--Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
<!--Servlet - JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
3、Maven资源过滤设置
<build>
<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>
4、相关配置文件
mybatis-config.xml (mybatis配置文件)
<?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>
<!-- 设置日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 别名-->
<typeAliases>
<package name="domain.Books" />
</typeAliases>
</configuration>
db.properties(数据库资源文件)
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/book?serverTimezone=UTC jdbc.username=root jdbc.password=1234
log4j.properties (日志配置文件)
#????DEBUG????????console?file???????console?file?????????
log4j.rootLogger=DEBUG,console,file
#??????????
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
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=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#??????
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
spring整合mybatis
spring-mybatis (Spring整合mybatis)
<?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.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置整合mybatis -->
<!-- 1.关联数据库文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 2.数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--连接池基本属性-->
<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="maxActive" value="20"/>
<property name="maxWait" value="9000"/>
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 4.配置扫描Dao接口包,动态实现mapper接口注入到spring容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="mapper"/>
</bean>
</beans>
spring整合MVC
web.xml (前端控制拦截器)
<?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">
<!--DispatcherServlet-->
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--encodingFilter-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--Session过期时间-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>
spring-mvc (spring整合mvc配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns: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
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置SpringMVC -->
<!-- 1.开启SpringMVC注解驱动 -->
<mvc:annotation-driven />
<!-- 2.静态资源默认servlet配置-->
<mvc:default-servlet-handler/>
<!-- 3.配置jsp 显示ViewResolver视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<context:component-scan base-package="controller"/>
</beans>
Spring整合Service
spring-service (spring管理service层配置文件)
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启service注解-->
<context:component-scan base-package="service"/>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
applicationContext.xml (spring总容器)
<?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.xsd">
<import resource="spring-mybatis.xml"/>
<import resource="spring-service.xml"/>
<import resource="spring-mvc.xml"/>
</beans>
五、文件上传
导入jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
添加mvc层配置
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
<property name="maxUploadSize" value="104857600"/>
<property name="defaultEncoding" value="utf-8"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
表单添加属性
<form action="/upFile" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
上传之后文件的保存,I/O流
Controller代码
@RequestMapping("/upFile")
public void upload(@RequestParam("file") MultipartFile file){
// 获得文件名 aa.jpg
String filename = file.getOriginalFilename();
String name=System.currentTimeMillis()+filename;
String path="F:/IDEA- WorkFile/javaweb_demo/JavaEEWork/shiyanbaogao/web/image/upload";
FileUpload.uploadFile(path,name,file);
}
工具类
public static void uploadFile(String path, String fileName, MultipartFile file) {
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
if (!file.isEmpty()) {
try {
FileOutputStream fileOutputStream = new FileOutputStream(path + "/" + fileName);
InputStream inputStream = file.getInputStream();
int b = 0;
while ((b = inputStream.read()) != -1) {
fileOutputStream.write(b);
}
fileOutputStream.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("文件上传到了--" + path + "/" + fileName);
}
浙公网安备 33010602011771号