框架
一套规范。
实际是他人实现的一系列接口和类的集合。通入导入对应框架的jar文件(maven项目导入对应的依赖),进行适当的配置,就能使用其中的所有内容。
开发者可以省去很多模板代码,如dao中的CRUD,MVC模式下层与层之间的关联。只需要集中精力实现项目中的业务逻辑部分。
Java主流框架
Spring、SpringMVC、MyBatis、MyBatisPlus、Hibernate、JPA等。
SSH:最初是Spring+Stucts2+Hibernate组成,之后Stucts2被SpringMVC取代。
SSM:Spring+SpringMVC+MyBatis
新项目使用SpringBoot,早起的SSH项目由于维护成本高,基本不会推翻重做,但会维护一些SSM项目。
无论是SSH还是SSM,Spring、SpringMVC必不可少。从2004年推出至今,依旧是主流框架中不可获取的一部分。
Spring
概念
一个轻量级开源的Java框架。是一个管理项目中对象的容器,同时也是其他框架的粘合器,目的就是对项目进行解耦。
轻量级:对原有代码的侵入很小。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ptN1p5iS-1676948376472)(https://bkimg.cdn.bcebos.com/pic/6a63f6246b600c337b73ab94174c510fd9f9a160?x-bce-process=image/watermark,image_d2F0ZXIvYmFpa2UxMTY=,g_7,xp_5,yp_5)]
Spring的核心是IOC控制反转和AOP面向切面编程
组成
名词解释
IOC
Inversion Of Control 控制反转
DI
Dependency Injection 依赖注入
举例说明
用代码描述场景:员工食堂每天提供事物
-
食物:米饭类
public class Rice{ public Rice(){ sout("今天吃米饭"); } }
-
食物:面条类
public class Noodles{ public Noodles(){ sout("今天吃面条"); } }
-
厨师类
public class Cook{ //定义一个做饭的方法,做什么饭new什么对象,创建食物对象的权限,是由当前厨师类决定。 public void cooking(){ //new Rice(); new Noodles(); } }
-
员工:main方法
psvm(){ Cook cook = new Cook(); cook.cooking(); }
这种方式,Cook类中的cooking()方法创建什么对象,就输出什么内容。(厨师做什么,员工就吃什么)。
如果有人想要吃指定食物,就要修改源代码cooking()方法中创建的对象。
解决方案:定义一个接口:Food
public interface Food{
void info();
}
让原本的所有食物Rice类和Noodles类实现该接口
public class Rice implements Food{
@Override
public void info(){
sout("今天吃米饭");
}
}
public class Noodles implements Food{
@Override
public void info(){
sout("今天吃面条");
}
}
给厨师Cook类中cooking()方法定义一个参数:Food接口
public class Cook{
public void cooking(Food food){
food.info();
}
}
这时Cook对象调用cooking()方法时,需要提供一个Food接口类型的实现类。
psvm(){
Cook cook = new Cook();
//传递什么参数,旧调用该参数重写后的方法
cook.cooking(new Rice());
cook.cooking(new Noodles());
}
整个过程中,将创建什么食物对象的控制权,由厨师交给用户,这就是控制反转(IOC)。
厨师对象调用cooking()方法的参数,就是对于食物Food对象的依赖,是由用户注入进来的,这就是依赖注入(DI)。
这样一来,各个对象之间互相独立(没有在某个类中new另一个类的对象),降低了代码之间的耦合度。
总结:控制反转(IOC)是一种思想,就是让创建对象的控制权由自身交给第三方,控制反转这种思想,通过依赖注入(DI)的方式实现。
IOC和DI其实都是在描述控制反转,IOC是思想,DI是具体实现方式。
这里的第三方,就是Spring。Spring是一个容器,可以管理所有对象的创建和他们之间的依赖关系。
可以理解为:“Spring就是用来管理对象的,在需要用到某个对象的时候,帮我们自动创建”。
如Servlet+JSP模式写Web项目时,会在控制层Servlet中创建业务逻辑层Service对象,在Service层中创建数据访问层Dao对象。
有了Spring后,就不会出现new这些对象的代码了。
Spring需要导入对应的jar文件后,定义一个配置文件,在该配置文件中配置程序运行过程中所需的对象。
AOP
Aspect Orintend Programming 面向切面编程
Spring控制台应用
1.创建一个普通的Maven项目,不选择模板
2.添加Spring核心依赖
jdk8用5.x版本
<!-- spring-context表示spring核心容器 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
3.创建一个Java类
package com.hqyj.spring01;
/*
* 定义一个普通的Java类
* PlainOrdinaryJavaObject pojo 相当于简化的javabean
* entity vo dto pojo 都是在描述实体类
* */
public class PlainOrdinaryJavaObject {
public void fun(){
System.out.println("一个PlainOrdinaryJavaObject(普通的Java类)对象");
}
}
4.创建Spring配置文件
创建一个Spring的配置文件,在其中注入上一步创建的类的对象
在resources目录下,创建一个xml文件,选择spring config,通常命名为application
<?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标签表示,在Spring容器中,注入某个类的对象-->
<!--class属性表示要注入哪个类,写类的全限定名(包名+类名)-->
<!--id表示给类的对象的名称-->
<bean class="com.hqyj.spring01.PlainOrdinaryJavaObject" id="pojo"></bean>
</beans>
5.创建main方法所在类
解析Spring配置文件,获取注入的对象。
package com.hqyj.spring01;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
//创建一个自定义类的对象
//传统方式创建对象
//PlainOrdinaryJavaObject pojo = new PlainOrdinaryJavaObject();
//使用spring容器获取对象
//创建一个用于解析Spring配置文件的对象,参数为配置文件的名称。实际就是获取Spring容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
//获取容器中的对象
/*
只通过名称获取,返回值为Object类型,需要转换
Object obj = context.getBean("pojo");
PlainOrdinaryJavaObject pojo=(PlainOrdinaryJavaObject) obj;
*/
//使用这种方式,直接用指定类型接收
PlainOrdinaryJavaObject pojo = context.getBean("pojo", PlainOrdinaryJavaObject.class);
//能成功调用方法,说明Spring管理了该类的对象
pojo.fun();
//关闭Spring容器
context.close();
}
}
思考
-
1.对象在什么时候创建?
默认情况下,在解析Spring配置文件的时候,自动创建一个对象。
-
2.如果不想在解析时自动创建怎么办?
在配置文件的某个
<bean>
标签中,添加一个"lazy-init=true"属性,表示该对象设置为懒加载,在初始化Spring容器时不会创建对象,只有在调用getBean()时才会创建对象
-
3.如果设置为懒加载,是不是每次调用getBean(),都会创建一个对象呢?
默认情况下,Spring容器只会创建一个对象。
在配置文件的某个
<bean>
标签中,添加一个"scope=‘prototype’"属性,表示每次调用getBean()方法,就会创建一个对象。该属性的值默认为"singleton",表示单例模式,只会创建一个对象。
总结:默认情况下,通过<bean>
标签定义的类,在Spring容器初始化时,创建一个对象。
bean标签常用属性
属性 | 作用 |
---|---|
class | 定义类的全限定名 |
id | 定义对象的名称 |
lazy-init | 是否为懒加载。默认值为false,在解析配置文件时就会创建对象。设置为true表示懒加载,只有在getBean()时才会创建对象。 |
scope | 单例/原型模式。默认值为singleton,表示单例模式,只会创建一个对象。设置为prototype,表示原型模式,每调getBean()就创建一个对象。 |
init-method | 初始化时触发的方法。在创建完该对象时自动调用的方法。该方法只能是无参方法,该属性的值只需要写方法名即可 |
destory-method | 销毁时触发的方法。Spring容器关闭时自动调用的方法,该方法只能是无参方法。只有在单例模式下有效。 |
属性注入
给某个bean添加属性的方式有两种:构造器注入和setter注入
setter注入
这种方式注入属性时,类中必须要有set方法
在bean标签中,加入<property></property>
标签,
该标签的name属性通常表示该对象的某个属性名,但实际是setXXX()方法中的XXX单词。
如有age属性,但get方法为getNianLing(),name属性就需要写成nianLing。
该标签的value属性表示给该类中的某个属性赋值,该属性的类型为原始类型或String。
该标签的ref属性表示给该类中除String以外的引用类型属性赋值,值为Spring容器中另一个bean的id。
<!--注入Car类对象并用set方式注入其属性-->
<bean class="com.hqyj.spring01.Car" id="c">
<!--该属性是字符串或原始类型,使用value赋值-->
<property name="brand" value="宝马"></property>
<!--name并不是类中是属性名,而是该属性对应的getXXX()方法中XXX的名称-->
<!--如Car类中有color属性,但get方法名为getColo(),这里就要写为colo-->
<property name="colo" value="白色"></property>
</bean>
<!--注入Person类对象并用set方式注入其属性-->
<bean class="com.hqyj.spring01.Person" id="p1">
<property name="name" value="王海"></property>
<property name="age" value="22"></property>
<!--属性是引用类型,需要通过ref赋值,值为另外的bean的id ref即references-->
<property name="car" ref="c"></property>
</bean>
构造方法注入
这种方式注入属性时,类中必须要有相应的构造方法
在bean标签中,加入<constructor-arg></constructor-arg>
标签,
该标签的name属性表示构造方法的参数名,index属性表示构造方法的参数索引。
赋值时,原始类型和字符串用value,引用类型用ref。
<!--注入Person类对象并用构造方法注入其属性-->
<bean class="com.hqyj.spring01.Person" id="p2">
<!--constructor-arg表示构造方法参数 name是参数名 index是参数索引-->
<constructor-arg name="name" value="张明"></constructor-arg>
<constructor-arg index="1" value="20"></constructor-arg>
<constructor-arg name="car" ref="c"></constructor-arg>
</bean>
复杂属性注入
/*
* 定义电影类
* */
public class Movie {
//电影名
private String movieName;
//导演
private String director;
//时长
private int duration;
//主演
private List<String> playerList;
//类型
private String movieType;
//放映时间,最终格式为yyyy/MM/dd HH:mm:ss
private String showTime;
}
List类型的属性
<!--注入Movie对象-->
<bean class="com.hqyj.spring01.Movie" id="movie1">
<property name="movieName" value="夏洛特烦恼"></property>
<property name="director" value="闫非、彭大魔"></property>
<property name="duration" value="87"></property>
<!--List类型属性赋值-->
<property name="playerList" >
<!--使用list标签-->
<list>
<!--如果集合中保存的是引用类型,使用ref标签-->
<!--如果集合中保存的是原始类型或字符串,使用value标签-->
<value>沈腾</value>
<value>艾伦</value>
<value>马丽</value>
</list>
</property>
<property name="movieType" value="喜剧"></property>
<property name="showTime" value="2010/06/01 0:0:0"></property>
</bean>
Set类型的属性
<!--注入PetShop对象-->
<bean class="com.hqyj.spring01.test3.PetShop" id="petShop">
<property name="shopName" value="xxx宠物店"></property>
<property name="petSet">
<!--Set类型的属性-->
<set>
<!--如果中保存的是原始类型或字符串,使用value子标签-->
<!--如果保存的是引用类型,使用ref子标签加bean属性设置对应的id-->
<ref bean="p1"></ref>
<ref bean="p2"></ref>
<ref bean="p3"></ref>
</set>
</property>
</bean>
Map类型的属性
<!--注入Cinema对象-->
<bean class="com.hqyj.spring01.Cinema" id="cinema">
<property name="name" value="万达影城"></property>
<property name="timeTable">
<!--Map类型属性赋值,标明键和值的类型-->
<map key-type="java.lang.Integer" value-type="com.hqyj.spring01.Movie">
<!--entry标签表示键值对 如果键值对都是原始类型或字符串,使用key和value-->
<!--如果键值对中有引用类型,使用key-ref或value-ref-->
<entry key="1" value-ref="movie1"></entry>
<entry key="2" value-ref="movie2"></entry>
</map>
</property>
</bean>
属性值如果通过某个方法调用而来
如使用String保存yyyy/MM/dd格式的日期,需要通过SimpleDateFormat对象调用parse()方法而来
<!--
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
-->
<!--注入SimpleDateFormat对象,设置日期格式-->
<bean class="java.text.SimpleDateFormat" id="sdf">
<!--如果构造方法注入时,该构造方法只有一个参数,可以不用写name或index-->
<constructor-arg value="yyyy/MM/dd"></constructor-arg>
</bean>
<!--
Date now = new Date();
-->
<!--注入Date对象-->
<bean class="java.util.Date" id="now"></bean>
<!--注入Pet对象-->
<bean class="com.hqyj.spring01.test3.Pet" id="p1">
<property name="petType" value="哈士奇"></property>
<property name="petNickName" value="小哈"></property>
<!--使用当前时间作为该属性的值,以yyyy/MM/dd-->
<!--
sdf.format(now);
-->
<property name="petBirthday">
<!--如果某个值是通过某个bean调用了某个方法而来-->
<bean factory-bean="sdf" factory-method="format">
<!--方法的实际参数-->
<constructor-arg ref="now"></constructor-arg>
</bean>
</property>
</bean>
属性自动注入autowire
以上所有案例中,如果要在A对象中注入一个引用类型的对象B,都是手动将对象B注入到对象A中。
如在Person中注入Car对象,在Cinema中注入Movie等。
这种情况下,如果当某个被注入的bean的id更改后,所有引用了该bean的地方都要进行修改。
所以将手动注入更改为自动注入(自动装配),就无需添加相应的<property>
标签,甚至可以无需定义bean的id。
实现自动注入
在某个bean标签中,加入autowire属性,设置值为"byName"或"byType"。通常设置为"byType"。
Car类
package com.hqyj.spring01.test1;
import java.util.HashMap;
public class Car {
private String brand;
private String color;
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", color='" + color + '\'' +
'}';
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Person类
package com.hqyj.spring01.test1;
public class Person {
private String name;
private int age;
private Car car;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", car=" + car +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
//自动注入时,必须要有该方法
//byType方式自动注入,会自动在容器中寻找该方法参数类型
//byName方式自动注入,会自动在容器中寻找该方法setCar中的car这个id
public void setCar(Car car) {
this.car = car;
}
}
配置文件
<?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">
<!--在容器中注入Car类型的bean-->
<bean class="com.hqyj.spring01.test1.Car" id="car">
<property name="brand" value="宝马"></property>
<property name="colo" value="白色"></property>
</bean>
<!--注入Person类的bean-->
<!--autowire="byType"表示自动检测该类中是否需要使用引用类型参数,如果容器中正好有唯一的一个对应类型的bean,就会自动赋值给对应的属性-->
<bean class="com.hqyj.spring01.test1.Person" id="person" autowire="byType">
<property name="name" value="赵明"></property>
<property name="age" value="26"></property>
</bean>
<!--autowire="byName"表示自动检测该类中的setXXX方法,如果某个setXXX方法的XXX和容器某个对象的id对应,就会自动赋值给对应的属性-->
<bean class="com.hqyj.spring01.test1.Person" id="person2" autowire="byName">
<property name="name" value="王海"></property>
<property name="age" value="26"></property>
</bean>
</beans>
Main
package com.hqyj.spring01.test1;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Person person = context.getBean("person", Person.class);
//此时打印时,会输出姓名、年龄和Car对象
System.out.println(person);
context.close();
}
}
autowire属性的值
-
byType
- 类中要有被注入的属性的setter()方法
- 被自动注入的对象可以没有id
- Spring容器中,某个对象的类型要与该setter()方法的参数类型一致,且容器中只有一个该类型的对象。
- 如setCar(Car c),Spring就会自动在容器中寻找类型为Car的对象自动装配
-
byName
- 类中要有被注入的属性的setter()方法
- 被自动注入的对象必须要有id
- 实际是根据setXXX()方法set后的单词XXX关联
- 如setCar(Car c),Spring就会自动在容器中寻找id为car的对象自动装配
在Web项目中,可以利用自动装配,在控制层中自动装配业务逻辑层的对象,在业务逻辑层中自动装配数据访问层的对象。
属性自动注入练习
在电影院案例的基础上
1.创建一个dao层CinemaDao类,包含Cinema对象,定义一个fun()方法,输出Cinema对象
package com.hqyj.spring01.test2.dao;
import com.hqyj.spring01.test2.Cinema;
/*
* 定义数据访问层
* 模拟查询数据库得到结果
* */
public class CinemaDao {
private Cinema cinema;
public void setCinema(Cinema cinema) {
this.cinema = cinema;
}
public void fun(){
System.out.println(cinema);
}
}
2.创建一个controller层CinemaController类,包含CinemaDao对象,定义方法fun()调用CinemaDao中的fun()方法
package com.hqyj.spring01.test2.controller;
import com.hqyj.spring01.test2.dao.CinemaDao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/*
* 定义控制层类,该层需要使用下一层dao中的方法
* */
public class CinemaController {
//这里无需创建对象,让Spring自动注入CinemaDao对象
private CinemaDao cinemaDao;
public void setCinemaDao(CinemaDao dao) {
this.cinemaDao = dao;
}
public void fun(){
cinemaDao.fun();
}
}
最终在Main方法中获取Controller对象后,调用fun()
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("movie.xml");
CinemaController controller = context.getBean("controller", CinemaController.class);
controller.fun();
}
配置文件
<!--省略movie对象-->
<!--注入Cinema对象-->
<bean class="com.hqyj.spring01.test2.Cinema" id="cinema">
<property name="name" value="万达影城"></property>
<property name="timeTable">
<!--Map类型属性赋值,标明键和值的类型-->
<map key-type="java.lang.Integer" value-type="com.hqyj.spring01.test2.Movie">
<!--entry标签表示键值对 如果键值对都是原始类型或字符串,使用key和value-->
<!--如果键值对中有引用类型,使用key-ref或value-ref-->
<entry key="1" value-ref="movie1"></entry>
<entry key="2" value-ref="movie2"></entry>
</map>
</property>
</bean>
<!--该类中有一个Cinema类型的属性,这里使用了autowire=byType自动装配,会在容器中寻找Cinema类型的对象自动赋值给属性-->
<bean class="com.hqyj.spring01.test2.dao.CinemaDao" autowire="byType"></bean>
<!--该类中有一个CinemaDao类型的属性,这里使用了autowire=byType自动装配,会在容器中寻找CinemaDao类型的对象自动赋值给属性-->
<bean class="com.hqyj.spring01.test2.controller.CinemaController" id="controller" autowire="byType"></bean>
Spring核心注解
在Spring配置文件中加入
<!--设置要扫描的包,扫描这个包下所有使用了注解的类-->
<context:component-scan base-package="com.hqyj.spring02.bookSystem"></context:component-scan>
类上加的注解
- @Component
- 当一个类不好归纳时,定义为普通组件
- @Controller
- 定义一个类为控制层组件
- @Service
- 定义一个类为业务层组件
- @Repository
- 定义一个类为持久层(数组访问层)组件
- @Lazy/@Lazy(value=true)
- 设置该类为懒加载。
- @Scope(value=“singleton/prototype”)
- 设置为单例/原型模式。
说明
以上注解公共特点
- 都是将对应类的对象注入到Spring容器中,用于替换配置文件中的bean标签
- 都默认是单例模式非懒加载
- 默认注入的对象id为当前类的类名首字母小写形式
- 如在BookDao类上添加,id默认为bookDao
- 可以通过注解的value属性自定义注入的对象的id名,如@Component(value=“key”)表示注入的对象id为key
属性上加的注解
-
@Autowired
-
优先使用byType方式从Spring容器中获取对应类型的对象自动装配。先检索Spring容器中对应类型对象的数量,如果数量为0直接报错;数量为1直接装配
数量大于1,会再尝试使用byName方式获取对应id的对象,但要配合@Qualifier(value=“某个对象的id”)一起使用,指定id进行装配
-
-
@Qualifier(value=“某个对象的id”)
- 配合@Autowired注解,使用byName方式获取某个对象id的bean进行装配
-
@Resource(name=“某个对象的id”)
-
该注解相当于@Autowired+@Qualifier(value=“某个对象的id”)
-
优先使用byName方式,从Spring容器中检索name为指定名的对象进行装配,如果没有则尝试使用byType方式,要求对象有且只有一个,否则也会报错。
-
说明
-
如果要在某个类中使用Spring容器中的某个对象时,只需定义成员变量,无需创建对象,通过@Autowired或@Resource注解进行自动装配
-
实际开发中,绝大部分情况下,需要自动装配对象有且只有一个,并且命名规范,所以@Autowired或@Resource区别不是很大。@Autowired优先使用byType方式,@Resource优先使用byName方式
-
如果@Resource不能使用,是因为缺少javax.annotation包,需要引入对应依赖
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
在Web项目中使用Spring
1.创建基于Maven的web-app项目
2.添加依赖
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--spring容器-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<!--web集成spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.23</version>
</dependency>
3.在main目录下创建java和resources目录,修改web.xml版本为4.0
4.在resources目录下创建Spring配置文件application.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"
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">
<!--扫描使用了Spring注解的根包-->
<context:component-scan base-package="com.hqyj.springweb"></context:component-scan>
</beans>
5.创建一个类,使用@Componet注解将其注入到Spring容器中
package com.hqyj.springweb.entity;
import org.springframework.stereotype.Component;
@Component
public class Pojo {
public void fun(){
System.out.println("hello springweb!");
}
}
如何初始化Spring容器(解析Spring配置文件)
在控制台应用程序中,可以在main方法中通过ClassPathXmlApplicationContext来解析Spring配置文件,初始化Spring容器。
在web项目中没有main方法,只有servlet中的service方法,如果在service方法中创建ClassPathXmlApplicationContext对象,会每次访问都执行。
而Spring容器只需初始化一次,在项目启动时就解析Spring配置文件,全局监听器就是一个很好的选择。
spring-web包中提供了一个ContextLoaderListener类,它实现了ServletContextListener,属于项目级别的全局监听器。
这个类需要一个contextConfigLocation参数,表示要解析的Spring配置文件的路径。
这个监听器会在项目启动时,读取指定的Spring配置文件路径,并且创建WebApplicationContext对象,即Spring容器。
6.在web.xml中配置监听器用于初始化Spring容器
<?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">
<!--配置监听器ContextLoaderListener-->
<listener>
<!--监听器全限定名-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--定义全局参数contextConfigLocation用于读取Spring配置文件-->
<context-param>
<!--参数名固定contextConfigLocation-->
<param-name>contextConfigLocation</param-name>
<!--只是Spring配置文件的路径 classpath:表示从根目录出发-->
<param-value>classpath:application.xml</param-value>
</context-param>
</web-app>
7.创建一个Servlet,访问该Servlet,获取Spring容器,从容器中获取注入的对象
package com.hqyj.springweb.controller;
import com.hqyj.springweb.entity.Pojo;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class MyServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Spring容器
WebApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
//从容器中获取某个bean
Pojo pojo = app.getBean("pojo", Pojo.class);
pojo.fun();
}
}
在Spring-web项目中使用Spring-jdbc
Spring提供了一套自己的JDBC解决方案,相较于自己写的JDBC,省去了繁琐的过程(获取连接、关闭),简化了对数据库的操作。
Spring-jdbc后续会用其他持久层框架代替,如MyBatis、JPA。
1.引入相关依赖
当前案例中核心的依赖是 spring-jdbc
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!--jstl-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--spring容器-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<!--web集成spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.23</version>
</dependency>
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.23</version>
</dependency>
2.创建包结构(controller、service、dao、entity),创建实体类
public class Hero {
private int id;
private String name;
private String position;
private String sex;
private int price;
private String shelfDate;
//省略get/set、构造方法、toString等
}
3.在Spring配置文件中配置数据源和JDBC模板
<?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">
<!--扫描使用了Spring注解的根包-->
<context:component-scan base-package="com.hqyj.springweb"></context:component-scan>
<!--配置数据源-->
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<!--配置MySQL驱动-->
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<!--配置MySQL地址-->
<property name="url" value="jdbc:mysql://localhost:3306/gamedb?serverTimezone=Asia/Shanghai"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置JDBC模板-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<!--设置要操作的数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
4.数据访问层(dao)的写法
package com.hqyj.springweb.dao;
import com.hqyj.springweb.entity.Hero;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class HeroDao {
@Autowired
//通过jdbc模板对象实现CRUD
private JdbcTemplate jdbcTemplate;
/*
* 查询所有
* */
public List<Hero> queryAll() {
//定义sql语句
String sql = "select * from hero";
//BeanPropertyRowMapper对象表示将查询到的字段与指定的类中的属性进行映射
BeanPropertyRowMapper<Hero> mapper = new BeanPropertyRowMapper<>(Hero.class);
//query()方法执行查询
List<Hero> list = jdbcTemplate.query(sql, mapper);
return list;
}
/*
* 删除
* */
public boolean delete(int id) {
String sql = "delete from hero where id=?";
int i = jdbcTemplate.update(sql, id);
return i > 0;
}
/*
* 修改
* */
public boolean update(Hero hero) {
String sql = "update hero set name=?,sex=?,position=?,price=?,shelf_date=? where id=?";
int i = jdbcTemplate.update(sql, hero.getName(), hero.getSex(), hero.getPosition(), hero.getPrice(), hero.getShelfDate(), hero.getId());
return i > 0;
}
/*
* 添加
* */
public boolean insert(Hero hero) {
String sql = "insert into hero values(null,?,?,?,?,?)";
int i = jdbcTemplate.update(sql, hero.getName(), hero.getSex(), hero.getPosition(), hero.getPrice(), hero.getShelfDate());
return i > 0;
}
/*
* 根据id查询
* */
public Hero findById(int id) {
String sql = "select * from hero where id=?";
BeanPropertyRowMapper<Hero> mapper = new BeanPropertyRowMapper<>(Hero.class);
Hero hero = jdbcTemplate.queryForObject(sql, mapper, id);
return hero;
}
}
忽略后续service、servlet、jsp等;
JDBCTemplate常用方法
方法 | 作用 | 说明 |
---|---|---|
query(String sql,RowMapper mapper) | 无条件查询 | 返回值为List集合 |
update(String sql) | 无条件更新(删除、修改) | 返回值为受影响的行数 |
query(String sql,RowMapper mapper,Object… objs) | 条件查询 | 可变参数为?的值 |
update(String sql,Object… objs) | 条件更新(增加、删除、修改) | 可变参数为?的值 |
queryForObject(String sql,RowMapper mapper) | 无条件查询单个对象 | 返回值为指定对象 |
queryForObject(String sql,RowMapper mapper,Object… objs) | 条件查询单个对象 | 返回值为指定对象 |
execute(String sql) | 执行指定的sql | 无返回值 |
AOP
概念
Process Oriented Programming 面向过程编程POP
Object Oriented Programming 面向对象编程OOP
Aspect Oriented Programming 面向切面编程AOP
以上都是编程思想,但AOP不是OOP和POP的替代,而是增强、拓展和延伸。主流编程思想依然是OOP。
作用
在传统的OOP思想中,我们将程序分解为不同层次的对象,通过封装、继承、多态等特性,
将对象组织成一个整体来完成功能。但在某些场景下,OOP会暴露出一些问题。
如在处理业务中,除了核心的业务代码外,通常还会添加一些如果参数验证、异常处理、事务、记录日志等操作。
这些内容会分散在各个业务逻辑中,依旧会出现大量重复操作。如果将这些重复的代码提取出来,在程序编译运行时,
再将提出来的内容应用到需要执行的地方,就可以减少很多代码量。方便统一管理,更专注于核心业务。
简单来说,就是将不同位置中重复出现的一些事情拦截到一处进行统一处理。
如图,这是用户模块的不同操作,其中除了核心业务之外,其余都是重复代码
将相同的位置进行切分
切分后
使用
一个普通业务层service类
package com.hqyj.springweb.service;
import com.hqyj.springweb.dao.HeroDao;
import com.hqyj.springweb.entity.Hero;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/*
* 一个普通业务层service类
* */
@Service
public class HeroService {
@Autowired
private HeroDao dao;
public List<Hero> queryAll() {
//在没有使用AOP时,比如要在执行前记录日志
//System.out.println("============");
//System.out.println("操作开始执行"+new Date());
System.out.println("xxx进行了查询操作");
//核心业务代码
List<Hero> list=dao.queryAll();
//在没有使用AOP时,比如要在执行后记录日志
//System.out.println("操作执行结束"+new Date());
//System.out.println("============");
return list;
}
public void delete(int id) {
//在没有使用AOP时,比如要在执行前记录日志
//System.out.println("============");
//System.out.println("操作开始执行"+new Date());
System.out.println("xxx删除了"+id);
//核心业务代码
dao.delete(id);
//在没有使用AOP时,比如要在执行后记录日志
//System.out.println("操作执行结束"+new Date());
//System.out.println("============");
}
}
提取在执行某个业务方法前后要执行的公共代码
package com.hqyj.springweb;
import org.springframework.stereotype.Component;
import java.util.Date;
/*
* 模拟各个业务中都要执行的记录日志的操作,单独定义在一个类中
* 将其注入到Spring容器中
* */
@Component
public class LogOperate {
public void start(){
System.out.println("============");
System.out.println("操作开始执行"+new Date());
}
public void end(){
System.out.println("操作执行结束"+new Date());
System.out.println("============");
}
}
在项目中添加AOP所需依赖
<!-- 切面织入包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<scope>runtime</scope>
</dependency>
在Spring配置文件中配置AOP
<!--配置AOP-->
<aop:config>
<!--配置切面(配置拦截后要做的事情)-->
<!--ref是提取出的公共代码所在类LogOperate在Spring容器中的id。由于使用了@Componet注解,默认id名为类名首字母小写-->
<aop:aspect ref="logOperate">
<!--配置切点(对哪个包中的哪个类、哪个方法执行的时候进行拦截)-->
<!--id是切点名,自定义-->
<aop:pointcut id="logPointcut" expression="execution(* com.hqyj.springweb.service..*.*(..))"/>
<!--配置前置增强(切点之前执行的方法)-->
<aop:before method="start" pointcut-ref="logPointcut"></aop:before>
<!--配置后置增强(切点之后执行的方法)-->
<aop:after method="end" pointcut-ref="logPointcut"></aop:after>
</aop:aspect>
</aop:config>
上面的配置代码中execution是切点指示符,小括号中是一个切点表达式,用于配置需要切入后增强处理的方法的特征
execution(* com.hqyj.springweb.service..*.*(..))
第一个*表示匹配所有方法的返回值
com.hqyj.springweb.service 表示匹配指定包
..* 表示匹配该包下的所有子包及所有类
.* 表示匹配该类下的所有方法
(..) 表示匹配所有参数类型和个数
整体表示在com.hqyj.springweb.service包中的一切类中的一切方法在执行前后,都会进入切入增强处理。
MVC
MVC设计思想并不是某个语言特有的设计思想,而是一种通用的模式。
是将一个应用分为三个组成部分:Model模型,View视图,Controller控制器
这样会降低系统的耦合度,提高它的可扩展性和维护性。
SpringMVC
在Web阶段中,控制层是由Servlet实现,传统的Servlet,需要创建、重写方法、配置映射。使用时极不方便,SpringMVC可以替换Servlet。
SpringMVC是Spring框架中位于Web开发中的一个模块,是Spring基于MVC设计模式设计的轻量级Web框架。
SpringMVC提供了一个DispatcherServlet的类,是一个Servlet。它在指定映射(通常设置为/或*.do)接收某个请求后,调用相应的模型处理得到结果,再通过视图解析器,跳转到指定页面,将结果进行渲染。
原理大致为:配置SpringMVC中的DispatcherServlet,将其映射设置为/或.do。*
如果是/表示一切请求先经过它,如果是*.do表示以.do结尾的请求先经过它,
它对该请求进行解析,指定某个Controller中的某个方法,这些方法通常返回一个字符串,
这个字符串是一个页面的名称,再通过视图解析器,将该字符串解析为某个视图的名称,跳转到该视图页面。
详细流程
使用SpringMVC
1.创建webapp项目
- 修改web.xml版本为4.0
- 创建java和resources目录
- 创建包结构
2.添加依赖
<!-- spring-webmvc -->
<!-- 这个依赖会包含spring-web和spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
3.配置初始化Spring
-
在resources目录下创建Spring配置文件application.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" 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"> <!--设置扫描使用了注解的根包--> <context:component-scan base-package="com.hqyj.springmvc"></context:component-scan> </beans>
-
在web.xml中使用监听器ContextLoaderListener初始化Spring
<?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"> <!--配置全局监听器初始化Spring--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--定义全局参数读取Spring配置文件--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.xml</param-value> </context-param> </web-app>
4.配置SpringMVC
-
在resources目录下创建配置SpringMVC的配置文件springmvc.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" 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">
<!--扫描控制层所在的包-->
<context:component-scan base-package="com.hqyj.springmvc.controller"></context:component-scan>
<!--配置内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--最终控制层跳转的页面所在的路径及页面自身后缀名-->
<!--jsp页面不建议直接通过浏览器访问。在WEB-INF目录下在资源,无法通过浏览器直接方法,所以将jsp保存在WEB-INF目录下,最好创建一个pages-->
<property name="prefix" value="/WEB-INF/pages/"></property>
<!--现阶段使用jsp输出数据,所以后缀为.jsp-->
<property name="suffix" value=".jsp"></property>
</bean>
- 在web.xml中配置DispatcherServlet
- 将该Servlet的请求映射设置为/,表示所有请求都会访问该Servlet,由该Servlet再进行分发
```xml
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--设置该Servlet的初始化参数,用于读取SpringMVC配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--设置该servlet的映射为/或*.do-->
<url-pattern>/</url-pattern>
</servlet-mapping>
5.在WEB-INF目录下创建一个pages目录,在其中创建一个welcome.jsp页面
- 通常jsp页面不允许被浏览器直接访问,需要保存在WEB-INF目录下
6.编写控制层代码
-
在controller包下创建一个类,加上@Controller注解
-
该类中定义的方法方法加入@RequestMapping()注解表示访问该方法的映射
-
该类中定义的方法返回值通常为字符串,表示某个页面的名称,也可以是另一个controller中的方法映射名
package com.hqyj.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; //加入@Controller注解表示该类是一个控制层类,替换之前的servlet @Controller //该注解如果只设置请求映射,直接填字符串 @RequestMapping("/first") public class HelloController { //该注解如果还有其他参数要设置,路径用path赋值 @RequestMapping(path="/hello") public String hello(){ //返回的字符串是某个页面的名称或另一个控制层中方法的请求映射 return "welcome"; } }
将项目部署到tomcat后,访问http://localhost:8080/SpringMVC_war_exploded/first/hello,即可跳转到指定页面
SpringMVC相关注解
-
@Controller
- 只能写在类上,表示该类属于一个控制器
-
@RequestMapping(“/请求映射名”)/@RequestMapping(value=“/请求映射名”)/@RequestMapping(path=“/请求映射名”)
- 该注解可以写在类或方法上。写在类上用于区分功能模块,写在类上用于区分具体功能
- 默认写一个属性或value或path后的值,都表示访问该类或该方法时的请求映射
-
@RequestMapping(value=“/请求映射名”,method=RequestMethod.GET/POST/PUT/DELETE)
- method属性表示使用哪种请求方式访问该类或该方法
- 如果注解中不止一个属性,每个属性都需要指定属性名
-
**@GetMapping(“/请求映射名”)**相当于@RequestMapping(value=“/请求映射名”,method=RequestMethod.GET)
- post、put、delete同理
- @GetMapping只能写在方法上
-
@PathVariable
-
该注解写在某个方法的某个形参上
-
通常配合@RequestMapping(“/{path}”)获取请求时传递的参数
@RequestMapping("/{path}") public String fun(@PathVariable("path") String pageName){ return pageName; } //当前方法如果通过"localhost:8080/项目名/hello"访问,就会跳转到hello.jsp //当前方法如果通过"localhost:8080/项目名/error"访问,就会跳转到error.jsp //映射中的/{path}就是获取路径中的hello或error,将其赋值给形参 //通常用于跳转指定页面
-
-
@RequestParam(value=“传递的参数名”,defaultValue =“没有传递参数时的默认值”)
- 该注解写在某个方法的某个参数上
- 用于获取提交的数据,可以设置默认值在没有提交数据时使用
控制层中获取请求时传递的参数
-
controller中方法的形参名和表单的name或?后的参数名一致
表单或a标签
<form action="${pageContext.request.contextPath}/first/sub"> <input type="text" name="username"> <input type="text" name="password"> <input type="submit" > </form> <a href="${pageContext.request.contextPath}/first/sub?username=admin">xxx</a>
controller
public String login(String username,int password){
//此时可以正常获取
//无关数据类型,但是提交数据时必须是对应的类型,否则会有400错误
}
-
controller中方法的形参名和表单的name或?后的参数名不一致
controller
public String login(@RequestParam(value="username",defaultValue="admin")String name,@RequestParam("username")int pwd){ //如果没有提交数据时,会使用设置的默认值 }
-
如果传递的参数都是某个实体类中的属性时
User类
package com.hqyj.springmvc.entity; public class User { private String username; private String password; @Override public String toString() { return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}'; } public User() { } public User(String username, String password) { this.username = username; this.password = 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; } }
controller
@RequestMapping("/login") public String login(User user){ //某个实体类的属性和提交的参数名一致时,可以直接将对象作为形参,会自动将对应参数赋值给对应属性 System.out.println(user); return ""; }
解决提交数据时的中文乱码
使用过滤器解决中文乱码。
在web.xml中配置spring-web提供的CharaterEncodingFilter过滤器
<!--定义解决中文乱码的过滤器CharacterEncodingFilter-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--设置编码格式-->
<init-param>
<!--该过滤器需要设置一个encoding属性,用于设置编码格式-->
<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>
将数据保存到作用域中
-
在controller中的某个方法的参数列表里添加Model参数
- 调用Model对象的addAttribute(String str,Object obj)方法,将某个obj对象保存在request作用域中,命名为str
@RequestMapping("/queryAll") public String queryAll(Model model){ ArrayList list = new ArrayList<>(); list.add("qwe"); list.add(123); list.add(true); list.add("哈哈"); //将list保存到request作用域中 model.addAttribute("list",list); //这种跳转属于请求转发 return "welcome"; }
-
在controller中的某个方法的参数列表里添加ModelAndView参数,同时将该方法的返回值设置为ModelAndView类型
- 使用ModelAndView对象调用addObject(String str,Object obj),将某个obj对象保存在request作用域中,命名为str
- 使用ModelAndView对象调用setViewName(String viewName),跳转到viewName页面
package com.hqyj.springmvc.controller; import com.hqyj.springmvc.service.HeroService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(“/hero”)
//如果要将数据保存到session中,使用该注解定义session中对象的名称
@SessionAttributes({“str1”,“str2”})
public class HeroController {
@Autowired
private HeroService heroService;
@RequestMapping("/queryAll")
public String queryAll(Model model){
model.addAttribute("list", heroService.queryAll());
return "heroList";
}
@RequestMapping("/showAll")
public ModelAndView queryAll(ModelAndView mav){
//默认保存查询出的对象到request中,命名为list
mav.addObject("list",heroService.queryAll());
//也可以保存到session
//mav.addObject("str1",heroService.queryAll());
//设置要跳转的页面
mav.setViewName("heroList");
return mav;
}
}
**数据都是保存在request作用域中**,在页面中使用jsp内置对象或EL获取。
如果要保存到session中,需要在类上加入@SessionAttributes({"str1","str2"})注解,str1,str2表示保存到session中的对象的名称,再在方法中,使用
Model对象的addAttribute(String str,Object obj)将其保存在session中。
# SpringMVC中的跳转
- 控制层跳转到某个jsp页面
- 在控制层中定义方法,这种方式跳转,属于请求转发
- 如果要使用重定向跳转,在页面名之前添加"redirect:"
```java
@RequestMapping("/hello")
public String hello(){
//返回页面名称
return "hello";//请求转发
}
@RequestMapping("/hello")
public ModelAndView hello(ModelAndView mav){
//设置页面名称
mav.setViewName("hello");
return mav;
}
-
在springmvc配置文件中
<mvc:view-controller path="请求映射" view-name="页面名称"></mvc:view-controller> <!-- 访问项目根目录,跳转到welcome.jsp页面 --> <mvc:view-controller path="/" view-name="welcome"></mvc:view-controller> <!-- 这个标签使用时,会让@RequesMapping失效,如果要共存,添加以下标签 --> <!--来自于xmlns:mvc="http://www.springframework.org/schema/mvc" --> <mvc:annotation-driven></mvc:annotation-driven>
-
控制层跳转到另一个控制层中的方法
-
方法的返回值为"redirect/forward:另一个控制层中方法的映射名"
@RequestMapping("/hello") public String hello(){ return "redirect:hero";//使用重定向的方式,跳转到映射名为hero的控制层 return "forward:hero"//使用请求转发的方式,跳转到映射名为hero的控制层 }
-
jsp页面跳转另一个jsp页面
-
当前项目中jsp页面都在WEB-INF下,无法直接访问,a标签同样如此,只能通过控制层跳转页面
-
定义用于跳转页面控制层类
package com.hqyj.springmvc.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /* * 定义一个用于跳转指定页面或controller的控制层 * */ @Controller public class ToPageController { /* 项目启动时或直接访问根目录,跳转到指定的controller */ @RequestMapping("/") public String toIndex() { return "redirect:/hero/queryAll"; } /* * 这个方法的作用:会将请求中第一个/后的单词截取出来命名为path赋值给参数page * 如 localhost:8080/web/hero,就会识别出hero,return "hero"; * 就会跳转到 /WEB-INF/pages/hero.jsp页面 * */ @RequestMapping("/{path}") public String toPage(@PathVariable("path") String page) { return page; } }
-
这时在页面中这样跳转
<%--这个路径实际是/项目名/addHero,会截取addHero,跳转到/项目名/WEB-INF/pages/addHero.jsp--%> <a href="${pageContext.request.contextPath}/addHero">添加</a>
文件上传
使用apche提供的通用文件上传组件实现。
1.导入所需依赖
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2.向Spring容器中注入上传文件的核心类
在application.xml中注入通用多部件解析器CommonsMultipartResolver
<!--注入上传文件的核心类:通用多部件解析器CommonsMultipartResolver-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<!--设置上传的单个文件最大字节 10M:1024*1024*10-->
<property name="maxUploadSizePerFile" value="10485760"></property>
</bean>
3.上传页面的表单
<!--上传的表单控件使用file-->
<!--提交方式为post-->
<!--添加enctype="multipart/form-data"属性-->
<form action="/upload" method="post" enctype="multipart/form-data">
请选择图片<input type="file" name="uploadFile">
<input type="submit" value="上传">
</form>
4.控制层获取上传的文件
package com.hqyj.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Controller
@RequestMapping("/admin")
public class UploadController {
@RequestMapping("/upload")
public String upload(@RequestParam("uploadFile") MultipartFile uploadFile) throws IOException {//uploadFile就是上传的文件对象
//获取上传的文件名
String oldName = uploadFile.getOriginalFilename();
//得到源文件的后缀名
String prefix = oldName.substring(oldName.lastIndexOf("."));
//有可能不同的人上传的文件名相同,所以获取源文件的后缀后,生成一个随机文件名,拼接新文件名。
String newName = UUID.randomUUID()+prefix;
//创建一个文件File对象,
File file = new File("d:\\上传文件夹", newName);
//将文件写入硬盘中
uploadFile.transferTo(file);
return "welcome";
}
}
如果要在某个页面中显示上传的文件,要配置一个虚拟目录
配置Spring+SpringMVC时用到的关键类
-
在web.xml中配置Spring全局监听器
-
ContextLoaderListener
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.xml</param-value> </context-param>
-
-
在Springmvc配置文件中配置SpringMVC内部资源视图解析器
-
InternalResourceViewResolver
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean>
-
-
在web.xml中配置SpringMVC请求分发Servlet
-
DispatcherServlet
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
-
在web.xml中配置字符编码过滤器
-
CharacterEncodingFilter
<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>
-
传的文件,要配置一个虚拟目录
配置Spring+SpringMVC时用到的关键类
-
在web.xml中配置Spring全局监听器
-
ContextLoaderListener
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.xml</param-value> </context-param>
-
-
在Springmvc配置文件中配置SpringMVC内部资源视图解析器
-
InternalResourceViewResolver
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean>
-
-
在web.xml中配置SpringMVC请求分发Servlet
-
DispatcherServlet
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
-
在web.xml中配置字符编码过滤器
-
CharacterEncodingFilter
<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>
-