本文为个人的学习笔记,仅作为学习记录笔记
Spring(IDEA)
一、概念
spring是分层的java SE/EE应用full-stack轻量级开源框架,以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核。
二、优势
- 提供IoC容器,解耦;
- AOP编程的支持
- 声明式事务的支持
- 方便测试
- 方便集成各种框架
- 降低javaEE API的使用难度(封装)
- java源码可供学习
三、开发步骤
-
导入Spring开发的基本坐标
-
编写Dao接口和实现类
-
创建Spring核心配置文件
-
在Spring配置文件中配置UserDaoImpl
-
使用Spring的API获得Bean实例(getBean参数为配置的id)
各步骤示例如下:
3/4
在recourses中创建Spring配置文件,文件名原则上随意取
5.
四、Spring配置文件
4.1、Bean标签基本配置
用于配置对象交由Spring来创建。默认情况下他调用的是类中的无参构造,没有无参构造不会创建。
基本属性:id:Bean实例在Spring容器中的唯一标识;class:Bean的全限定名称
4.2、Bean标签范围配置
scope:指对象的作用范围,取值有:
- singleton:默认值,单例的(在Spring中只会创建一个对象。多次new都只是同一个对象。spring核心文件加载时创建Bean对象)
- prototype:多例的(在Spring中可创建/new多个对象。在使用时"getBean()"创建Bean对象)
- request:Web中,Spring创建一个Bean对象,将对象存入到request域中
- session:Web中,Spring创建一个Bean对象,将对象存入session域中
- global session:在Web中,应用在portlet环境,如没有该环境,就等同于session
4.3、Bean的生命周期
-
init-method:初始化方法
-
destroy-method:销毁方法
4.4、Bean实例化的三种方式
- 无参构造方法
- 工厂静态方法(factory-method)
- 工厂实例方法(factory-bean、factory-method)
4.5、Bean依赖注入
- 通过set方法
-
name:set的属性(userDao);ref:容器中的目标对象id(userDao)
- 通过构造方法
依赖注入数据类型:
-
普通数据类型
-
引用数据类型(如上userService引用userDao)
-
集合数据类型
4.6、import导入其他分标签
<import resource="applicationContext.xml"></import>
五、相关API
5.1、ApplicationContext
5.2、getBean()
- getBean(“id”):当存在多个相同的类时,只能使用id方式获取
- getBean(class):当某个类只存在一个时,可使用类来获取,不需要强转
六、连接池
6.1、c3p0
-
手动直接连接方式(导包)
导入的mysql的包版本在8.0以上要使用"com.mysql.cj.jdbc.Driver"驱动,并修改url中的时区问题
-
加载配置文件方式(.properties文件)
-
Spring配置数据源
-
Spring加载外部配置文件来配置数据源
需要注意,该配置方式需要在context命名空间中配置;同时使用SPEL表达式来设置内容
6.2、druid
-
手动直接使用方式
需要注意时区问题
-
Spring配置数据源
七、注解开发
7.1、原始注解
-
@Component :标准一个普通的spring Bean类
-
@Repository:标注一个DAO组件类
@Repository("userDao") public class userDaoImpl implements userDao { }
-
@Service:标注一个业务逻辑组件类
@Service("userService") public class userServiceImpl implements userService { }
-
@Controller:标注一个控制器组件类
-
@Autowired:属于Spring 的org.springframework.beans.factory.annotation包下,可用于为类的属性、构造器、方法进行注值
-
@Qualifier(""):按照id名称从容器中匹配,需要结合Autowired
@Autowired @Qualifier("userDao") private userDao userdao; //使用注解方式可以不用写set
-
@Resource():不属于spring的注解,使用该annotation为目标bean指定协作者Bean;相当于@Autowired+@Qualifier("")
@Resource(name = "userDao") private userDao userdao;
-
@Value():注入普通属性
@Value("${jdbc.driver}") private String Driver;
-
@Scope():标注Bean的作用范围
-
@PostConstruct:标注在方法上,表示该方法是Bean的初始化方法
-
@PreDestroy:标注在方法上,表示该方法是Bean的销毁方法
注意,在使用竹节时,需要在配置文件中扫描注解,基包为扫描对象及其子包:
<context:component-scan base-package="com.zjj.maven"/>
7.2、新注解
-
@Configuration:声明当前类是一个配置类(相当于一个Spring配置的xml文件)
-
@ComponentScan:自动扫描指定包下所有使用@Service,@Component,@Controller,@Repository的类并注册
<context:component-scan base-package="com.zjj.maven"/> //相当于
-
@Bean:注解在方法上,声明当前方法的返回值为一个Bean。注册一个Bean,值为方法的返回值
-
@PropertySource:指定文件地址。提供了一种方便的、声明性的机制,用于向Spring的环境添加PropertySource。与@configuration类一起使用。
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> //相当于
-
@Import(xxx.class):导入文件
具体实例:
//核心配置文件(总配置类)
@Configuration //标记为配置类
@ComponentScan("com.zjj.maven") //扫描范围
@Import(dataSourceConfig.class) //导入文件
public class springConfiguration {
}
//分配置类,通过import导入注配置类
@PropertySource("classpath:jdbc.properties") //导入properties文件
public class dataSourceConfig {
@Value("${jdbc.driver}") //注入普通数据类型
private String Driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource") //注册一个Bean,为方法的返回值
public DataSource getDataSource()throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(Driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
}
//加载配置类
ApplicationContext app = new AnnotationConfigApplicationContext(springConfiguration.class);
userService userService = (userService)app.getBean("userService");
DataSource dataSource = (DataSource) app.getBean("dataSource");
Connection conn = dataSource.getConnection();
7.3、springJunit集成测试
- 导入spring集成junit坐标
- @Runwith代替原来的运行期
- @ContextConfiguration指定配置文件或类
- @Autowired注入测试对象
- 创建测试放进行测试
如下:
<!--导入集成junit坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
@RunWith(SpringJUnit4ClassRunner.class) //代替原来的 运行期
//@ContextConfiguration("classpath:applicationContext.xml") //指定配置文件
@ContextConfiguration(classes = {springConfiguration.class}) //指定配置类
public class springJunitTest {
@Autowired //注入数据
private userService userService;
@Autowired
private DataSource dataSource;
@Test
public void test2() throws Exception{
Connection conn = dataSource.getConnection();
System.out.println(conn);
conn.close();
}
@Test
public void test1(){
userService.save();
}
}
八、AOP
AOP(Aspect Oriented Programming:面向切面编程)
8.1、代理模式
-
静态代理
-
继承:通过继承父类,重写方法实现
//目标对象 public class Target { public void save(){ System.out.println("saving..."); } }
//代理对象 public class Proxy extends Target { @Override public void save() { System.out.println("before"); //增强 super.save(); } }
//使用代理对象 public class test { public static void main(String[] args) { Proxy proxy = new Proxy(); proxy.save(); } } //输出: //before //saving...
-
聚合:通过实现接口来实现代理
//接口 public interface Inte { public void save(); }
//目标对象 public class Target implements Inte{ @Override public void save() { System.out.println("saving"); } }
//代理对象 public class Proxy implements Inte { private Target target; public Proxy(Target tar){ this.target = tar; } @Override public void save() { System.out.println("before...");//增强 target.save(); System.out.println("after...");//增强 } }
//实现 public class test { public static void main(String[] args) { Target tar = new Target(); Proxy proxy = new Proxy(tar); proxy.save(); } } //输出: //before... //saving... //after...
-
-
动态代理(JDK)兄弟关系
//接口 public interface TargetInterface { public void save(); }
//目标对象 public class Target implements TargetInterface { @Override public void save() { System.out.println("save..."); } }
//增强方法 public class Advice { public void before(){ System.out.println("before..."); } public void after(){ System.out.println("after..."); } }
//代理实现 public class PorxyTest { public static void main(String[] args) { //目标对象 Target target = new Target(); //增强对象 Advice advice = new Advice(); //返回值,动态生成的代理对象;newProxyInstance包含三个参数 TargetInterface invoke = (TargetInterface) Proxy.newProxyInstance( target.getClass().getClassLoader(), //目标对象类加载器 target.getClass().getInterfaces(), //目标对象相的接口字节码对象数组,因此可代理多个接口的对象 new InvocationHandler() { //调用代理对象的任何方法,实质上调用的时invoke的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { advice.before(); //前置增强 Object invoke = method.invoke(target, args); //执行目标方法 advice.after(); //后置增强 return invoke; } } ); //调用代理对象方法 invoke.save(); } } //输出: //before... //save... //after...
-
动态代理(cglib)父子关系
//目标对象 public class Target implements TargetInterface { @Override public void save() { System.out.println("save..."); } }
//增强方法 public class Advice { public void before(){ System.out.println("before..."); } public void after(){ System.out.println("after..."); } }
//创建代理并实现 public class PorxyTest { public static void main(String[] args) { //目标对象 Target target = new Target(); //增强对象 Advice advice = new Advice(); //动态代理对象。基于cglib //1.创建增强器 Enhancer enhancer = new Enhancer(); //2.设置父类(目标) enhancer.setSuperclass(Target.class); //3.设置回调 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { advice.before(); //前置方法 Object invoke = method.invoke(target, args); //目标对象方法 advice.after(); //后置方法 return invoke; } }); //创建代理对象 Target invoke = (Target) enhancer.create(); invoke.save(); } } //输出: //before... //save... //after...
8.2、相关概念
- Target(目标对象):代理的目标对象
- Porxy(代理):一个类被AOP织入增强后,就产生一个代理类
- Joinpoint(连接点):能够被拦截到的方法,泛指方法
- Pointcut(切入点):对哪些连接点进行拦截的定义
- Advice(通知/增强):拦截到连接点后需要做的事情
- Aspect(切面):时切入点和通知的结合
- Weaving(织入):将增强应用到目标对象来创建代理的过程
8.3、xml方式配置
-
配置步骤:
-
导入AOP相关坐标
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
-
创建目标接口和目标类(内部有切点)
//目标类 public class Target implements TargetInterface { @Override public void save() { System.out.println("save..."); } }
-
创建切面类(内部有增强方法)
public class MyAspect { public void before(){ System.out.println("before..."); } public void after(){ System.out.println("after..."); } }
-
将目标类和切面类的对象创建权交给spring
-
在applicationContext.xml中配置织入关系
<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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="target" class="com.zjj.maven.aop.Target"></bean> <bean id="MyAspect" class="com.zjj.maven.aop.MyAspect"></bean> <aop:config> <!--织入配置--> <aop:aspect ref="MyAspect"> <!--确定切面--> <aop:before method="before" pointcut="execution(public void com.zjj.maven.aop.Target.save())"></aop:before> <!--确定切点和增强:前置--> <aop:after method="after" pointcut="execution(public void com.zjj.maven.aop.Target.save())"></aop:after> <!--确定切点和增强:后置--> </aop:aspect> </aop:config> </beans>
-
测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class aopTest { @Autowired private TargetInterface tar; @Test public void test(){ tar.save(); } } //输出: //before... //save... //after...
-
-
切点表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 修饰符可省略
- 返回值类型、包名、类名、方法名可以使用*代表任意
- 包名与类名之间一个.代表当前包下的类,两个…表示当前包及其子包的类
- 参数列表可以使用两个点…表示任意参数
-
通知的类型:
-
前置通知
<aop:before>
-
后置通知
<aop:after-returning>
-
环绕通知
<aop:around>
-
异常抛出通知
<aop:throwing>
-
最终通知
<aop:after>
-
8.4、注解方式配置
-
配置步骤:
-
创建目标接口类和目标类
@Component("Target") public class Target implements TargetInterface { @Override public void save() { System.out.println("save..."); } }
-
创建切面类
-
将目标类和切面类的对象创建权交给spring
-
在切面类中使用注解配置织入关系
@Component("MyAspect") @Aspect //设置切面 public class MyAspect { @Before("execution(public void com.zjj.maven.aop_anno.*.*(..))") //织入 public void before(){ System.out.println("before..."); } public void after(){ System.out.println("after..."); } }
-
在配置文件中开启扫描和AOP的自动代理
<context:component-scan base-package="com.zjj.maven.aop_anno"></context:component-scan> <!--组件扫描--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!--aop自动代理-->
-
测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext_anno.xml") public class aop_annoTest { @Autowired private TargetInterface target; @Test public void test(){ target.save(); } } //输出: //before... //saving...
-
-
注解类型:
-
通知注解类型
- @Before — 前置通知
- @AfterReturning — 后置通知
- @Around — 环绕通知(目标对象默认不执行,需要手动执行)
- @After — 最终通知
- @AfterThrowing — 异常抛出通知
-
切点表达式抽取
@After("pointcut()") //直接使用抽取的切点表达式的方法 public void after(){ System.out.println("after..."); } //在切面类中定义一个方法,为该方法添加注解Pointcut,内容为切点表达式 @Pointcut("execution(public void com.zjj.maven.aop_anno.*.*(..))") public void pointcut(){}
-
九、Spring jdbcTemplate
9.1、开发步骤:
-
导入相关坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.5.RELEASE</version> </dependency>
-
创建数据库表和实体
-
创建jdbcTemplate对象
<!--配置文件配置,并创建对象--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/student?serverTimezone=UTC&useSSL=false"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>
//加载配置文件 ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); JdbcTemplate jdbc = app.getBean(JdbcTemplate.class);
-
执行数据库操作
int row = jdbcTemplate.update("insert into t_user (id,username,password,hobby,email) values (?,?,?,?,?)", "1111111", "zhangsan", "123456", "hobby", "4565464"); System.out.println(row);
9.2、CURD:
-
增删改
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestCURD { @Autowired private JdbcTemplate jdbc; @Test public void testAdd() { jdbc.update("insert into user (id,name) values (?,?)", "1", "zhangsan"); } @Test public void TestUpdate() { jdbc.update("update user set name=? where id=?", "lisi", "1"); } @Test public void TestDelete(){ jdbc.update("delete from user where name=?","lisi"); } }
-
查
@Test /*查询全部数据,参数为:sql+bean属性行映射(封装到实体类中),返回值为集合*/ public void TestQueryAll(){ List<UserEntity> list = jdbc.query("select * from user", new BeanPropertyRowMapper<UserEntity>(UserEntity.class)); System.out.println(list); } @Test /*查询单个数据,参数为:sql+bean属性行映射(封装到实体类中)+参数,返回值为对象*/ public void TestQueryOne(){ UserEntity sd = jdbc.queryForObject("select * from user where name=?", new BeanPropertyRowMapper<UserEntity>(UserEntity.class), "sd"); System.out.println(sd); } @Test /*查询数量,返回值为简单数据类型,参数为类型.class*/ public void TestQueryCount(){ Integer count = jdbc.queryForObject("select count(*) from user", Integer.class); System.out.println(count); }
十、声明式事务控制
10.1、xml方式
实例:
-
DAO
public class accountDaoImpl implements accountDao { private JdbcTemplate jdbc; public accountDaoImpl (JdbcTemplate jdbcTemplate){this.jdbc = jdbcTemplate;} @Override public void updateIn(String InName,double Inmoney) { int update = jdbc.update("update myaccount set money=money+? where username=?", Inmoney, InName); } @Override public void updateOut(String OutName,double Outmoney) { int update = jdbc.update("update myaccount set money=money-? where username=?", Outmoney, OutName); } }
-
SERVICE
public class accountServiceImpl implements accountService { private accountDao accountDao; public accountServiceImpl(accountDao accountDao){this.accountDao = accountDao;} @Override public void transimt(String Outname, String InName, double money) { accountDao.updateIn(InName,money); int a = 5/0; accountDao.updateOut(Outname,money); } }
-
CONTROLLER
public static void main(String[] args) { ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); accountService bean = (accountService) app.getBean("accountService"); bean.transimt("zhangsan","lisi",5000); }
-
XML
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/account?serverTimezone=UTC&useSSL=false"></property> <property name="user" value="root"></property> <property name="password" value="root"></property> </bean> <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountDao" class="com.zjj.maven.Dao.Impl.accountDaoImpl"> <constructor-arg ref="template"></constructor-arg> </bean> <!--目标对象--> <bean id="accountService" class="com.zjj.maven.Service.Impl.accountServiceImpl"> <constructor-arg ref="accountDao"></constructor-arg> </bean> <!--配置平台事务管理器--> <bean id="transactionManagement" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--通知,事务增强--> <tx:advice id="tx-ddvice" transaction-manager="transactionManagement"> <tx:attributes> <tx:method name="*"/> <tx:method name="save" isolation="DEFAULT" timeout="-1" read-only="false" propagation="MANDATORY"/> </tx:attributes> </tx:advice> <!--method: 切点事务参数配置 name:切点方法名 isolation:事务隔离级别 propagation:事务传播行为 timeout:超时事件 read:事都只读 --> <!--织入--> <aop:config> <aop:advisor advice-ref="tx-ddvice" pointcut="execution(* com.zjj.maven.Service.Impl.accountServiceImpl.transimt(..))"></aop:advisor> </aop:config>
10.2、注解方式
-
为Dao、Service类添加注解使其注册到spring容器中(@Repository(“accountDao”)、@Service(“accountService”))
-
在xml中配置扫描组件
<context:component-scan base-package="maven"/> <!--扫描注解-->
-
为切点增加通知和织入
@Transactional(isolation = Isolation.DEFAULT) //可添加事务参数配置,可配置在类上(表示该泪下全部);可配置在方法上(就近原则) public void transimt(String Outname, String InName, double money) { accountDao.updateIn(InName,money); int a = 5/0; accountDao.updateOut(Outname,money); }
-
咋xml中配置注解事务驱动
<tx:annotation-driven transaction-manager="transactionManagement"/> <!--注解事务驱动-->
十一、Spring集成Web开发环境
11.1、开发环境
-
POM.xml配置
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.5.RELEASE</version> </dependency>
2.Web层application文件加载(将加载放在ContextLoaderListener监听器中,输入spring封装工具)
<!--web.xml配置-->
<!--全局初始化参数 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--配置监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
@WebServlet("/test")
public class userServlet extends HttpServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
ServletContext servletContext = req.getServletContext(); //获得ServletContext域对象
//使用WebApplicationContextUtils工具类自动在监听器中加载xml配置文件,并返回一个ApplicationContext对象
ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(servletContext);
userServiceImpl bean = app.getBean(userServiceImpl.class);
bean.save();
}
}
SpringMVC
一、开发步骤
-
导入SpringMVC相关坐标 (pom.xml)
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.5.RELEASE</version> </dependency>
-
配置SpringMVC核心控制器DispathcerServlet (web.xml)
<!--springMVC前段控制器配置--> <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:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
创建Controller类和视图界面
-
使用注解配置Controller类中业务方法的映射地址
@Controller("userController") public class userController { @RequestMapping("/saving") public String saving(){ System.out.println("userController runner..."); return "success.jsp"; //跳转界面 } }
-
配置SpringMVC核心文件spring-mvc.xml
<contrext:component-scan base-package="com.zjj.web01.Controller"></contrext:component-scan>
-
测试
二、注解解析
2.1、@RequestMapping
-
用于建立请求URL和建立请求方法之间的对应关系
-
可作用于类上(URL的一级目录,相当于根目录)和方法上(URL的二级目录)
-
参数:value method params
@RequestMapping(value = "/saving",method = RequestMethod.POST,params = {"aaa"})
2.2、@ResponseBody
- 用于回写数据
- 告知SpringMVC框架,不进行试图跳转,直接返回数据
2.3、@RequestBody
-
该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上
-
再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
-
处理格式:application/json, application/xml等,置于方法参数前
public void test5(@RequestBody List<userEntity> list){ System.out.println(list); }
2.4、@RequestParam
-
用于绑定请求参数与方法的参数;当请求参数名与方法名不一样时且请求参数与方法参数不匹配时,将请求参数映射到参数上
-
注解参数:
- value:请求参数的名称
- required:请求参数是否允许为空(否:true;是:false)
- defaultValue:默认值
//请求:http://localhost:8080/getValue/query6?name=xxx
@RequestMapping("query6")
@ResponseBody
public void test6(@RequestParam(value = "name",required = false, defaultValue = "aaa") String username) {
System.out.println(username);
}
//输出
//xxx
2.5、@PathVariable
-
用于Restful风格的参数设置
-
请求参数通过url路径来传输,而是不用连接符携带传输
//请求:http://localhost:8080/getValue/query7/zhangsan @RequestMapping("query7/{username}") //需要在路径后添加占位符,即实际参数 @ResponseBody public void test7(@PathVariable(value = "username") String username) { //使用注解解析,value应与占位符内相同 System.out.println(username); } //输出 //zhangsan
2.6、@RequestHeader
- 获得请求头信息
- 参数:
- value:请求头中具体信息
- required:是否必须包含该信息(true:是,false:否)
//获得请求头中的content_type信息
@RequestMapping("query9")
@ResponseBody
public void test9(@RequestHeader(value = "content-type",required = false) String content_type) {
System.out.println(content_type);
}
2.7、@CookieValue
- 获得请求的Cookie值
- 参数
- value:请求头中具体信息
- required:是否必须包含该信息(true:是,false:否)
//获得JSESSIONID
@RequestMapping("query10")
@ResponseBody
public void test10(@CookieValue(value = "JSESSIONID") String jsessionId) {
System.out.println(jsessionId);
}
//直接得到JSESSIONID字符串
三、Spring_mvc.xml配置相关
3.1、资源内部视图解析器配置
<!--内部资源视图解析器配置-->
<bean id="InternalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"></property> <!--配置视图资源前置信息-->
<property name="suffix" value=".jsp"></property> <!--配置视图资源后缀信息-->
</bean>
//在@ResquestMapping注解映射的方法中,可以胜率一些重复的信息
return "success"; //如果不配置,则应写的资源路径为:"/jsp/success.jsp"
3.2、处理器映射器配置
<!--配置处理器映射器-->
<bean id="RequestMappingHandlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
</list>
</property>
</bean>
(通过该项配置,可以使在回写数据时,SpringMVC框架自动将类转换成json格式回写)
该配置可以简化:
<mvc:annotation-driven></mvc:annotation-driven> <!--由此代替上面的配置信息-->
3.3、静态资源开放
SpringMVC 默认不开放静态资源
-
方法一
使用mvc:resources标签,mapping表示webapp下的路径,”/“可视为webapp文件夹;location表示哪个目录下的资源开放,一般为"/xx/"格式
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
-
方法二
开放所有静态文件资源(当SpringMVC找不到静态资源时,tomcat服务器会去寻找,即开放所有)
<mvc:default-servlet-handler></mvc:default-servlet-handler>
3.4、文件上传解析器
配置文件上传解析器即可实现文件上传,此处使用CommonMutipartResolver来配置(也可使用StandardServletMutipartResolver配置,区别在于:后者需要依赖servlet3.0以上版本;前者基于apache不需要该版本依赖,只需要导入依赖包即可commons-fileupload,详见6.2)。
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="500000"></property>
</bean>
需要注意:在配置时,bean的id应为"multipartResolver",应为在源码中,spring默认会自动从上下文中寻找id为multipartResolver的bean作为MultipartResolver,如修改,会导致上传失败
3.5、拦截器配置
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--对哪些资源进行拦截-->
<mvc:mapping path="/**"/>
<bean class="com.zjj.maven.interceptor.Myinterceptor1"></bean> <!--拦截器类全限定名-->
</mvc:interceptor>
</mvc:interceptors>
3.6、异常处理配置
-
简单异常处理器配置
<!--简单异常处理器--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="defaultErrorView" value="error"></property> <!--默认异常跳转视图--> <property name="exceptionMappings"> <map> <entry key="java.lang.ClassCastException" value="error1"></entry> <!--如果出现此异常,进入类型转换异常视图--> <entry key="java.lang.ArithmeticException" value="error2"></entry> <!--如果出现此异常,进入除数为0常视图--> </map> </property> </bean>
-
自定义异常处理器
<!--只需要将异常处理类加入到容器中即可--> <bean class="com.zjj.maven.Resolver.MyExceptionResolver"></bean>
四、SpringMVC的数据响应
4.1、页面跳转
-
直接返回字符串
@RequestMapping(value = "/saving",params = {"aaa"}) public String saving(){ System.out.println("userController runner..."); return "forward:/jsp/success.jsp"; //转发 }
@RequestMapping(value = "/saving",params = {"aaa"}) public String saving(){ System.out.println("userController runner..."); return "redirect:/jsp/success.jsp"; //重定向 }
-
通过ModelAndView对象返回
@RequestMapping(value = "/saving2") public ModelAndView saving2(){ //返回ModelAndView ModelAndView modelAndView = new ModelAndView(); //设置模型数据 modelAndView.addObject("username","zjj"); //类似于request域的setAttrabute //设置试图名称 modelAndView.setViewName("forward:/jsp/success.jsp"); //页面跳转,使用重定向将无法将数据发送至页面(request域同理) return modelAndView; }
<p>username:${username}</p> <!--重定向将无法接收到模型中的数据-->
-
mode 和 view分开
@RequestMapping(value = "/saving3") public String saving3(Model model){ //注入model //设置模型数据 model.addAttribute("username","zjj"); return "/jsp/success.jsp"; }
4.2、回写数据
-
直接返回字符串
@RequestMapping(value = "/saving4") @ResponseBody //告知SpringMVC框架,不进行试图跳转,直接返回数据 public String saving4(){ //返回数据 return "HELLO WORLD"; }
实例应用:
@RequestMapping(value = "/saving5") @ResponseBody //告知SpringMVC框架,不进行试图跳转,直接返回数据 public String saving5() throws JsonProcessingException { //实体对象 userEntity userEntity = new userEntity(); userEntity.setUserName("zjj"); userEntity.setAge(21); //json转化 ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(userEntity); //返回数据 return json; }
-
返回对象或集合
//此方式需要配置 处理器映射器 ;详细配置信息可见3.2 @RequestMapping(value = "/saving6") @ResponseBody //告知SpringMVC框架,不进行试图跳转,直接返回数据 public userEntity saving6(){ //实体对象 userEntity userEntity = new userEntity(); userEntity.setUserName("zjj"); userEntity.setAge(21); //返回数据 return userEntity; }
五、SpringMVC获得请求数据
5.1、获得请求的参数
-
基本类型参数 (直接在Controller类中方法中传入相关数据名称参数即可)
//请求:/query1?name=zjj&age=15&sex=nan @RequestMapping("query1") @ResponseBody public void test1(String name, int age, String sex){ //传入请求中的相关参数的名称 System.out.println(name); System.out.println(age); System.out.println(sex); }
-
POJO类型参数 (传入实体类,可自动封装到实体类中)
//请求:/query2?name=zjj&age=15 @RequestMapping("query2") @ResponseBody public void test2(userEntity userEntity){ //传入如请求中参数一致的实体类,MVC将自动将数据封装至实体类中 System.out.println(userEntity); }
-
数组类型参数
//请求:/query3?str=gggg&str=pppp&str=saaaaa @RequestMapping("query3") @ResponseBody public void test3(String []str){ //传入与参数名称相同的数组 System.out.println(Arrays.asList(str)); }
-
集合类型参数
需要创建一个VO类封装有实体类的集合,将表单数据传入该集合实现封装
//VO类 public class VO { private List<userEntity> userList; //泛型为实体类的集合 public List<userEntity> getUserList() { return userList; } public void setUserList(List<userEntity> userList) { this.userList = userList; } @Override public String toString() { return "vo{" + "userList=" + userList + '}'; } }
//Controller @RequestMapping("query4") @ResponseBody public void test4(VO vo){ //传入VO类 System.out.println(vo); }
<!--表单--> <form action="/getValue/query4" method="post"> 用户1的id:<input name="userList[0].userName"><br> 用户1的age:<input name="userList[0].age"><br> 用户2的id:<input name="userList[1].userName"><br> 用户2的age:<input name="userList[1].age"><br> <input type="submit" value="提交"> </form>
案例二:(使用注释加ajax类传输获得集合数据)
@RequestMapping("query5")
@ResponseBody
public void test5(@RequestBody List<userEntity> list){ //@RequestBody使用该注释可直接获得集合,详见2.3
System.out.println(list);
}
<!--ajax请求-->
<body>
<script src="/js/jquery-3.5.1.js"></script>
<script>
var userList = new Array();
userList.push({"userName":"aaa","age":16});
userList.push({"userName":"bbb","age":18});
$.ajax({
type:"POST",
url:"${pageContext.request.contextPath}/getValue/query5",
contentType:"application/json;charset=utf-8",
data : JSON.stringify(userList) /*转化为json格式数据*/
});
</script>
</body>
需要注意:SpringMVC默认不开放静态资源(如js、css等静态文件夹中的资源),需要配置开放静态资源,详见3.3
5.2、请求乱码问题
通过web.xml配置全局过滤设置编码
<!--配置全局过滤filter-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5.3、自定义类型转换器
步骤:
-
定义转换器类实现Converter接口
public class DateConverter implements Converter<String,Date>{ //请求参数类型,转换类型 @Override public Date convert(String s) { SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd"); Date date = null; try { date = format.parse(s); } catch (ParseException e) { e.printStackTrace(); } return date; //返回日期 } }
-
在配置文件中声明转换器
<!--声明自定义转换器--> <bean id="conversionServiceFactory" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="com.zjj.web01.converter.DateConverter"></bean> <!--绑定自定义转换器的全限定名--> </list> </property> </bean>
-
在<annotation - driven> 中引用转换器
<mvc:annotation-driven conversion-service="conversionServiceFactory"></mvc:annotation-driven>
-
测试
//请求:http://localhost:8080/getValue/query8?date=2021-1-25 @RequestMapping("query8") @ResponseBody public void test8(Date date) { System.out.println(date); } //输出: //Mon Jan 25 00:00:00 CST 2021
六、文件上传
6.1、文件上传三要素
-
表单项type=“file”
-
表单的提交方式时post
-
表单的enctype属性时多部分表单形式,即enctype=“multipart/form-data”
<form action="/file/load1" method="post" enctype="multipart/form-data"> 名称:<input name="name"/><br> 文件:<input type="file" name="file"/><br> <input type="submit" value="上传"/> </form>
6.2、单文件上传步骤
-
导入fileipload和io坐标
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
-
配置文件上传解析器
<!--配置文件上传解析器,详见3.4--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"></property> <property name="maxUploadSize" value="500000"></property> </bean>
-
编写文件上传代码
@RequestMapping(value = "load1",method = RequestMethod.POST) @ResponseBody public void test1(String name, MultipartFile file){ System.out.println(name); //获得文件名 String originalFilename = file.getOriginalFilename(); try { //将文件写入服务器磁盘,该方法为其自带方法 file.transferTo(new File("C:\\Users\\18264\\Desktop\\学习文档\\"+ originalFilename)); } catch (IOException e) { e.printStackTrace(); } }
6.3、多文件上传
-
表单
<form action="/file/load1" method="post" enctype="multipart/form-data"> 名称:<input name="name"/><br> 文件1:<input type="file" name="file"/><br> <!--文件name相同--> 文件2:<input type="file" name="file"/><br> <input type="submit" value="上传"/> </form>
-
文件上传代码
@RequestMapping(value = "load1",method = RequestMethod.POST) @ResponseBody public void test1(String name, MultipartFile[] file){ //使用数组接收 System.out.println(name); try { for(MultipartFile m : file){ //遍历存盘 String originalFilename = m.getOriginalFilename(); file.transferTo(new File("C:\\Users\\18264\\Desktop\\学习文档\\"+ originalFilename)); } } catch (IOException e) { e.printStackTrace(); } }
七、SpringMVC拦截器
- SpringMVC拦截器相当于 servlet 中的 filter
- SpringMVC拦截器也是AOP的一种具体体现
7.1、Filter与SpringMVC拦截器
Filter | SpringMVC | |
---|---|---|
拦截范围 | 整个Web项目中可以使用 | 只能在MVC框架中使用 |
拦截对象 | 可以拦截所有资源(包括servlet和静态资源js、css等) | 只能拦截Controller中的方法,不能拦截静态资源 |
7.2、拦截器实现步骤
-
创建拦截器类实现HandlerInterceptor接口
public class Myinterceptor1 implements HandlerInterceptor { //在目标方法执行之前执行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true; //设置为true,放行 } //在目标方法执行之之后,视图(view)返回之前 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } //在目标方法整个流程执行完毕之后执行 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
-
配置拦截器
<!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <!--对哪些资源进行拦截--> <mvc:mapping path="/**"/> <bean class="com.zjj.maven.interceptor.Myinterceptor1"></bean> </mvc:interceptor> </mvc:interceptors>
-
测试拦截器的拦截效果
//输出: //preHandle //目标资源执行 //postHandle //afterCompletion
八、SpringMVC异常处理机制
8.1、简单异常处理器:SimpleMappingExceptionResolver
-
异常处理器配置
<!--异常处理器,,,详见3.6--> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="defaultErrorView" value="error"></property> <!--默认异常跳转视图--> <property name="exceptionMappings"> <map> <entry key="java.lang.ClassCastException" value="error1"></entry> <!--如果出现此异常,进入类型转换异常视图--> <entry key="java.lang.ArithmeticException" value="error2"></entry> <!--如果出现此异常,进入除数为0常视图--> </map> </property> </bean>
-
Controller
@Controller("exception") public class ExceptionConTest { @Autowired private userService userService; //除数为0异常 @RequestMapping("exception2") public String show2() throws Exception{ userService.show2(); return "index"; } //类型转换异常 @RequestMapping("exception1") public String show1() throws Exception{ userService.show1(); return "index"; } }
-
Service
public class userService { //类型转换异常 public void show1(){ System.out.println("类型转换异常"); Object str = "xxx"; Integer num = (Integer) str; } //除数为0异常 public void show2(){ System.out.println("除数异常"); int num = 5/0; } }
8.2、自定义异常处理:HandlerExceptionResolver
-
创建异常处理器类实现HandlerExceptionResolver
public class MyExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView modelAndView = new ModelAndView(); //新建ModelAndView对象用于返回 if (e instanceof ClassCastException){ //如果异常为ClassCastException modelAndView.addObject("info","ClassCastException"); modelAndView.setViewName("error1"); }else if(e instanceof ArithmeticException){ //如果异常为ArithmeticException modelAndView.addObject("info","ArithmeticException"); modelAndView.setViewName("error2"); } return modelAndView; //返回模型视图 } }
-
配置异常处理器
<bean class="com.zjj.maven.Resolver.MyExceptionResolver"></bean> <!--自定义异常处理只需要将异常处理类全限定名加入容器即可-->
-
编写异常页面
<!--error--> <body> <p>类型转换异常</p><br> ${info} </body>
public String show2() throws Exception{
userService.show2();
return “index”;
}
//类型转换异常
@RequestMapping(“exception1”)
public String show1() throws Exception{
userService.show1();
return “index”;
}
}- Service ```java public class userService { //类型转换异常 public void show1(){ System.out.println("类型转换异常"); Object str = "xxx"; Integer num = (Integer) str; } //除数为0异常 public void show2(){ System.out.println("除数异常"); int num = 5/0; } }
8.2、自定义异常处理:HandlerExceptionResolver
-
创建异常处理器类实现HandlerExceptionResolver
public class MyExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView modelAndView = new ModelAndView(); //新建ModelAndView对象用于返回 if (e instanceof ClassCastException){ //如果异常为ClassCastException modelAndView.addObject("info","ClassCastException"); modelAndView.setViewName("error1"); }else if(e instanceof ArithmeticException){ //如果异常为ArithmeticException modelAndView.addObject("info","ArithmeticException"); modelAndView.setViewName("error2"); } return modelAndView; //返回模型视图 } }
-
配置异常处理器
<bean class="com.zjj.maven.Resolver.MyExceptionResolver"></bean> <!--自定义异常处理只需要将异常处理类全限定名加入容器即可-->
-
编写异常页面
<!--error--> <body> <p>类型转换异常</p><br> ${info} </body>
-
测试异常跳转