spring,主要内容有两点:IOC,AOP。AOP里面spring独到的事务处理。
系统架构讲究上层依赖于下层
Spring Framework 学习路线
第一部分:核心容器(核心概念IOC/DI、容器基本操作)
第二部分:整合:整合数据层技术MyBatis
第三部分:AOP(核心概念、AOP基础操作、AOP实用开发)
简单通俗来讲:在dao层和service层中,要想在service层中使用dao对象,就需要 new 一个对象,这样就与“低耦合高内聚”思想背道而驰,然后为了解决这个问题,就有了IOC和DI。
IOC和DI是一种思想,Bean是一种对象,IOC容器是管理bean对象的一种容器
spring程序开发基本步骤
1.导入相关依赖坐标
2.编写dao接口和实现类
3.创建spring配置文件,并在配置文件中创建Bean
4.使用Spring的Api获取Bean实例
applicationContext.xml
<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="bookDao" class="com.chen.dao.daoImpl.BookDaoImpl">bean>
<bean id="bookService" class="com.chen.service.serviceImpl.BookServiceImpl">
<property name="bookDao" ref="bookDao">property>
bean>
beans>
//main中
//3.获取IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//4.获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.bookDao();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.bookService();
//Service层中
//5.删除业务层中使用new的形式创建dao对象
// private BookDao bookDao = new BookDaoImpl();
private BookDao bookDao;
@Override
public void bookService() {
bookDao.bookDao();
System.out.println("bookService...");
}
//6.提供set方法
public void setBookDao(BookDao bookDao){
this.bookDao=bookDao;
}
基本属性
id:Bean标签在spring容器中的唯一标识
class:Bean的全限定类名
作用:配置对象交由spring来控制
默认调用的是对象的无参构造方法,如果没有无参构造方法就会创建失败。
scope:标识对象的作用范围,常见取值如下
取值范围 | 说明 |
---|---|
singleton | 默认值,单例,整个程序使用一个实例 |
prototype | 多例的,每个请求一个创建一个新示例 |
request | WEB项目中,Spring创建一个Bean对象,将对象放到request域中 |
session | WEB项目中,Spring创建一个Bean对象,将对象放到session域中 |
global session | WEB项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession相当于session |
1)使用无参构造方法
<Bean id="", class=""><Bean/>
2)工厂静态方法实例化
public class StaticFactoryBean {
public static BookDao createBookDao(){
return new BookDaoImpl();
}
}
<bean id="bookDao" class="com.chen.StaticFactoryBean" factory-method="createBookDao">bean>
3)工厂实例方法实例化
public class FactoryBean {
public BookDao createBookDao(){
return new BookDaoImpl();
}
}
<bean id="FactoryBean" class="com.chen.FactoryBean">bean>
<bean id="bookDao" factory-bean="FactoryBean" factory-method="createBookDao">bean>
4)FactoryBean
public class BookDaoFactoryBean implements FactoryBean<BookDao> {
//代替原始实例工厂中创建对象的方法
@Override
public BookDao getObject() throws Exception {
return new BookDaoImpl();
}
//实例的对象对应类的字节码
@Override
public Class<?> getObjectType() {
return BookDaoImpl.class;
}
//是否单例
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
<bean id="bookDao" class="com.chen.BookDaoFactoryBean">bean>
提供生命周期
public class BookDaoImpl implements BookDao {
@Override
public void bookDao() {
System.out.println("BookDao...");
}
//Bean初始化对应操作
public void init(){
System.out.println("init...");
}
//Bean销毁前对应的操作
public void destroy(){
System.out.println("destroy...");
}
}
配置生命周期控制方法
<bean id="bookDao" class="com.chen.dao.daoImpl.BookDaoImpl" init-method="init" destroy-method="destroy">bean>
<bean id="bookService" class="com.chen.service.serviceImpl.BookServiceImpl">
<property name="bookDao" ref="bookDao">property>
<bean>
测试方法
public class App {
public static void main(String[] args) {
//3.获取IOC容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//4.获取bean
// BookDao bookDao = (BookDao) ctx.getBean("bookDao");
// bookDao.bookDao();
BookService bookService = (BookService) ctx.getBean( "bookService");
bookService.bookService();
ctx.registerShutdownHook();//虚拟机关闭之前,把容器先关掉,这句代码写在哪里都行
//ctx.close();//直接关闭,放在前面就直接关闭了
}
}
public class BookServiceImpl implements BookService , InitializingBean, DisposableBean {
private BookDao bookDao;
@Override
public void bookService() {
bookDao.bookDao();
System.out.println("bookService...");
}
public void setBookDao(BookDao bookDao){
System.out.println("setBookDao... ");
this.bookDao=bookDao;
}
@Override
public void destroy() throws Exception {
System.out.println("service destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {//在属性创建之后执行
System.out.println("service init...");
}
}
1.设置set方法
2.配置bean
<bean id="bookDao" class="com.chen.dao.daoImpl.BookDaoImpl" init-method="init" destroy-method="destroy">bean>
<bean id="bookService" class="com.chen.service.serviceImpl.BookServiceImpl">
<--Bean类型-->
<property name="bookDao" ref="bookDao">property>
<--基本类型-->
<property name="databaseName" value="abc">property>
bean>
1.设置构造器
2.配置bean,注意此时的name为形参,其他与setter注入一致。(这是基本模式)
还有一种模式,不写名字,写类型type,这样可以解耦,与形参名称不耦合
<bean id="bookDao" class="com.chen.dao.daoImpl.BookDaoImpl" init-method="init" destroy-method="destroy">bean>
<bean id="bookService" class="com.chen.service.serviceImpl.BookServiceImpl">
<--Bean类型-->
<constructor-arg name="bookDao" ref="bookDao">constructor-arg>
<--基本类型-->
<constructor-arg type="java.lang.String" value="abc">constructor-arg>
bean>
这样虽然解耦,但是如果形参是两个相同类型的,就无法使用,于是有了下面写法,给出参数位置index
<bean id="bookDao" class="com.chen.dao.daoImpl.BookDaoImpl" init-method="init" destroy-method="destroy">bean>
<bean id="bookService" class="com.chen.service.serviceImpl.BookServiceImpl">
<--Bean类型-->
<property name="bookDao" ref="bookDao">property>
<--基本类型-->
<property index="0" type="java.lang.String" value="abc">property>
bean>
构造器:强制依赖,必须要有的
setter方法:可选依赖,不一定要有的
在有必要的情况下可以两种都用,自己开发中推荐使用setter
<bean id="bookService" class="com.chen.service.serviceImpl.BookServiceImpl" autowire="byName">
自动装配特征
<bean id="bookDao" class="com.chen.impl.BookDaoImpl">
<property name="array">
<array>
<value>100value>
<value>200value>
<ref bean="beanId"/>
<array>
<property>
<property name="map">
<map>
<entry key = "contry" value="china"/>
<entry key = "province" value="gansu"/>
<map>
<property>
<property name="properties">
<props>
<prop key="p1">aaaprop>
<prop key="p2">bbbprop>
<prop key="p3">cccprop>
props>
property>
<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
">
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
<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>
<bean id="bookDao" class="com.chen.dao.daoImpl.BookDaoImpl">
<property name="name" value="${username}"/>
bean>
beans>
加载配置文件的两种方式:
//类路径加载配置文件
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\IdeaProjects\\spring_datasource\\src\\main\\resources\\applicationContext.xml");
//加载多个配置文件
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");
获取bean
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
//按照类型,前提该类型的bean唯一
BookDao bean = ctx.getBean(BookDao.class);
初始化bean的时候可以设置延迟加载(加载配置文件时不构造对象)
<bean
id="bookDao" bean的Id
name="dao BookDaoImpl daoImpl" bean的别名
class="com.chen.dao.daoImpl.BookDaoImpl" bean类型,静态工厂类,FactoryBean类
scope="singleton" 控制bean的实例数量,单列,多例
init-method="init" 生命周期初始化方法
destroy-method="destroy" 生命周期销毁方法
autowire="byType" 自动装配类型
factory-method="getInstance" bean工厂方法,应用于静态工厂或实例工厂
factory-bean="com.itheima.factory.BookDaoFactory" 实例化工厂bean
lazy-init="true" 控制bean延迟加载
/>
@Component
public class BookServiceImpl implements BookService {
}
@Component("bookDao")
public class BookDaoImpl implements BookDao {
}
<context:component-scan base-package="com.chen"/>
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
}
@Service
public class BookServiceImpl implements BookService {
}
Spring3.0开启纯注解开发模式,使用java类代替配置文件
@Configuration
@Component("com.chen")
public class SpringConfig {
}
@ComponentScan({"com.chen.service","com.itheima.dao"})
//获取容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
@Scope("singleton")
public class BookDaoImpl implements BookDao {
@PostConstruct//构造方法之后
public void init(){
System.out.println("init...");
}
@PreDestroy//销毁之前
public void destroy(){
System.out.println("destroy...");
}
}
public class App1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
System.out.println(bookDao);
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
ctx.close();
}
}
使用@Autowired注解开启自动装配模式
@Autowired
@Qualifier("bookDao1")
private BookDao bookDao;
@Value("123")
private String name;
@Configuration
@ComponentScan("com.chen")
@PropertySource("jdbc.properties")
public class SpringConfig {
}
@Value("${name}")
private String name;
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
//2.添加@Bean,表示当前方法的返回值是一个bean,可以添加名字@Bean("dataSource")
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/tlias");
ds.setUsername("root");
ds.setPassword("2002");
return ds;
}
}
//这里有两种方式,@Import是第一种,多个用数组
//第二种是给JdbcConfig也加上@Configuration注解,然后再SpringConfig 里面加上@ComponentScan组件扫描
@Configuration
@Import({JdbcConfig.class})
public class SpringConfig {
}
将MyBatis的xml配置文件写成配置类,
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.10.RELEASEversion>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.0version>
dependency>
2.编写数据源配置类和数据源
public class JdbcConfig {
@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
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
数据配置jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/tlias?useSSL=false
jdbc.username=root
jdbc.password=2002
3.创建MyBatis配置类
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
//自动扫描并注册配置实体类的别名
ssfb.setTypeAliasesPackage("com.chen.domain");
//配置数据源
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
//设置mapper接口的包路径
msc.setBasePackage("com.chen.dao");
return msc;
}
}
4.创建主配置类
@Import({JdbcConfig.class, MybatisConfig.class})
@ComponentScan("com.chen")
@Configuration
@PropertySource("jdbc.properties")
public class SpringConfig {
}
5.编写主类
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountService accountService = ctx.getBean(AccountService.class);
List<Account> all = accountService.findAll();
System.out.println(all);
}
}
//设定类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//指定Spring配置类的注解,告诉Spring加载应用程序上下文
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testFindById(){
.......
}
}
1.导入相关依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.10.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
2.定义通知类,编写 通知,下面代码的method方法
3.定义切入点,下面代码的pt()方法
4.定义切面(绑定切入点与通知的关系),指定通知添加到原始方法的具体位置,这里的@Before(“pt()”)注解
5.交给Spring处理,添加@Component
@Aspect注解,并在Spring配置类中添加@EnableAspectJAutoProxy
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.chen.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
}
@Configuration
@ComponentScan("com.chen")
@EnableAspectJAutoProxy//开启注解格式AOP功能
public class SpringConfig {
}
1.spring容器启动
2.读取所有切面配置的切入点
3.初始化bean,判断bean对应的类中的方法是否匹配到任意切入点
@Pointcut("execution(public void com.chen.dao.BookDao.findById(int))")
通配符
对于切入点表达式的编写其实是很灵活的,那么在编写的时候,有没有什么好的技巧让我们用用:
五种类型,可以写pt(),也可以写成类名.pt()
//因为不知道程序会不会有异常,所以要抛出异常
@Around("pt()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.printIn("around before advice ...");
//获取当前的类名和方法名,可以输出日志等等,
Signature signature = pjp.getSignature();
String className = signature.getDeclaringTypeName();
String methodName = signature.getName();
//表示原始操作的调用
pjp.proceed();
System.out.printIn("around before advice ...");
}
//对原始方法调用后,如果原始方法有返回值,需要接收返回值,并且把通知方法设置Object返回值
用JoinPoint或者ProceedingJoinPoint的getArgs接收参数
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(String com.chen.dao.BookDao.findName(int))")
private void pt(){}
//接收参数示例
@Before("pt()")
public void method(JoinPoint jp){
Object[] args = jp.getArgs();
System.out.println(Arrays.toString(args));
System.out.println("before advice...");
System.out.println(System.currentTimeMillis());
}
//接收参数和返回值示例
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args));
args[0] = 666;
return pjp.proceed(args);
}
//接收返回值示例
@AfterReturning(value = "pt()",returning = "ret")
//写上接收返回值的形参名,如果有JoinPoint jp,这个必须为第一个参数
public void afterReturning(JoinPoint jp,Object ret){//定义一个接收返回值的形参
System.out.println("afterReturning advice..."+ret);
}
}
//接收异常示例
@Around("pt()")
public Object around(ProceedingJoinPoint pjp){
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args));
args[0] = 666;
try {
return pjp.proceed(args);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
//接收异常示例
@AfterReturning(value = "pt()",returning = "throwable")
//写上接收异常的形参名,如果有JoinPoint jp,这个必须为第一个参数
public void afterReturning(JoinPoint jp,Throwable throwable){//定义一个接收异常的形参
System.out.println("afterReturning advice..."+throwable);
}
1.一般在业务层接口上添加Spring事务管理@Transactional,降低耦合。当然也可以添加在接口,方法和实现类上。
2.设置事务管理器
//配置事务管理器,mybatis使用的是jdbc事务,这个PlatformTransactionManager 类是Spring官方提供
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
3.开启注解式事务驱动
//开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}
public interface LogService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
void log(String out, String in, Double money);
}
做表现层开发,相当于Servlet。
1.导入maven依赖,SpringMVC坐标与Servlet坐标
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.28version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.0version>
dependency>
dependencies>
2.创建SpringMVC控制器类(等同于servlet功能)
@Controller
public class UserController {
@ResponseBody
@RequestMapping("/sava")
public String save(){
System.out.println("User模块的save功能正在执行");
return "SpringMVC:save";
}
}
3.初始化SpringMVC环境(同Spring环境),设定SpringMVC加载对应的bean
@Configuration
@ComponentScan("com.chen.controller")
public class SpringMvcConfig {
}
4.初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求。
//定义一个Servlet容器启动的配置类,在里面加载spring的配置
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//加载SpringMVC容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置哪些请求归属SpringMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载spring容器配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}
简写
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
//设置哪些请求归属SpringMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载SpringMVC容器配置
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
//加载Spring容器配置
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringConfig.class};
}
//POST请求中文乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
ServletContainersInitConfig
类,初始化web容器createServletApplicationContext
方法,创建了WebApplicationContext
对象WebApplicationContext
对象加载SpringMvcConfig
@ComponentScan
加载对应的beanUserController
,每个@RequestMapping
的名称对应一个具体的方法localhost:8080/save
/save()
/save
匹配执行对应的方法save()
mvc控制controller中的bean,spring控制service和dao中的bean
@Configuration
//使用MyBatis配置类,可以不写扫描dao包,但是写上通用性更高,不写的话如果数据层换成别的技术就不适配了。
@ComponentScan({"com.chen.service","com.chen.dao"})
public class SpringMvcConfig {
}
方式二:设定精准扫描范围为service,dao等
@Configuration
@ComponentScan(value = "com.chen",
excludeFilters = @ComponentScan.Filter(
//过滤方式,这里为根据注解过滤
type = FilterType.ANNOTATION,
//过滤的注解类型,这里为过滤@Controller
classes = Controller.class
)
)
public class SpringMvcConfig {
}
- 方式三:不区分Spring和SpringMVC的环境,加载到同一个环境中
@ResponseBody
@RequestMapping("/sava")
public String save(String name,Integer age){
return R.success();
}
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "{'module':'pojo param'}";
}
注意:
如果POJO对象中嵌套了其他的POJO类,如
public class Address {
private String province;
private String city;
//setter...getter...略
}
public class User {
private String name;
private int age;
private Address address;
//setter...getter...略
}
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "{'module':'pojo param'}";
}
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
return "{'module':'array param'}";
}
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
System.out.println("集合参数传递 likes ==> "+ likes);
return "{'module':'list param'}";
}
1、SpringMVC默认使用的是jackson来处理json的转换,所以需要在pom.xml添加jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.0version>
dependency>
@Configuration
@ComponentScan("com.itheima.controller")
//开启json数据类型自动转换
@EnableWebMvc
public class SpringMvcConfig {
}
4.参数前添加@RequestBody
//使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)参数传递 list ==> "+likes);
return "{'module':'list common for json param'}";
}
//Date默认格式是yyyy/MM/dd HH:mm:ss
//@DateTimeFormat的pattern设置格式
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,@DateTimeFormat(pattern="yyyy-MM-dd")Date date1){
System.out.println("参数传递date"+date);
System.out.println("参数传递date1"+date1);
return "{'module':'data param'}";
}
@Controller
public class UserController {
@RequestMapping("/toJumpPage")
//注意
//1.此处不能添加@ResponseBody,如果加了该注入,会直接将page.jsp当字符串返回前端
//2.方法需要返回String
public String toJumpPage(){
System.out.println("跳转页面");
return "page.jsp";
}
}
@Controller
public class UserController {
@RequestMapping("/toText")
//注意此处该注解就不能省略,如果省略了,会把response text当前页面名称去查找,如果没有回报404错误
@ResponseBody
public String toText(){
System.out.println("返回纯文本数据");
return "response text";
}
}
@Controller
public class UserController {
@RequestMapping("/toJsonPOJO")
@ResponseBody
public User toJsonPOJO(){
System.out.println("返回json对象数据");
User user = new User();
user.setName("itcast");
user.setAge(15);
return user;
}
}
出现异常现象的常见位置与常见诱因如下:
//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice{
//除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
@ExceptionHandler(Exception.class)
public R doException(Exception ex){
return new R.success(null)
}
}
package com.chen.exception;
public class SystemException extends RuntimeException{//继承RuntimeException,异常向上抛出到controller
private Integer code;
public SystemException(Integer code,String message) {
super(message);
this.code = code;
}
public SystemException( Integer code,String message, Throwable cause) {
super(message, cause);
this.code = code;
}
public SystemException( Integer code,Throwable cause) {
super(cause);
this.code = code;
}
}
2、将其他异常包成自定义异常
@GetMapping("/{id}")
public R<Book> getById(@PathVariable Integer id){
//模拟业务异常,包装成自定义异常
if (id==1){
throw new BusinessException("请不要用你的技术挑战我的耐性!!!");
}
//模拟系统异常,将有可能出现的异常进行包装,转换成自定义异常
try{
int i = 1/0;
}catch (Exception e){
throw new SystemException("服务器访问超时,请重试");
}
return R.success(bookService.getById(id));
}
3、处理器中处理自定义异常
@RestControllerAdvice
public class ProjectControllerAdvice {
//除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
@ExceptionHandler(Exception.class)
public R doException(){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return R.error("系统繁忙,请稍后再试");
}
//@ExceptionHandler用于设置当前处理器类对应的异常类型
@ExceptionHandler(SystemException.class)
public R doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return R.error(ex.getMessage());
}
@ExceptionHandler(BusinessException.class)
public R doBusinessException(BusinessException ex){
return R.error(ex.getMessage());
}
}
1、声明拦截器bean ,并实现HandlerInterceptor接口(注意:扫描加载bean)
在controller包下新建interceptor包
@Component
public class ProjectInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle......");
return true;
}
@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......");
}
}
2、定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法(注意:扫描加载配置),添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个。
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}