目录

  • 一. 容器标记类注解
  • 1.1 @Controller
  • 1.2 @Service
  • 1.3 @Repository
  • 1.4 @Component
  • 1.6 @RestController
  • 1.7 @Bean
  • 二. 注入类注解
  • 2.1 @Autowired
  • 2.2 @Qualifier
  • 2.3 @Resource
  • 2.5 @Primary
  • 2.6 @Import
  • 2.6.1 class数组的方式
  • 2.6.2 实现ImportSelector接口
  • 2.6.3 实现ImportBeanDefinitionRegistrar 接口
  • 三. 配置文件类注解
  • 3.1 @Configuration
  • 3.2 @Value
  • 3.3 @ConfigurationProperties
  • 3.4 Environment对象
  • 3.5 @PropertySource
  • 3.6 @SpringBootConfiguration
  • 四. URL处理类注解
  • 4.1 @RequestMapping
  • 4.2 @GetMapping
  • 4.3 @PostMapping
  • 4.4 @RequestParam
  • 4.5 @PathVariable
  • 五. 初始化类
  • 5.1 @InitBinder
  • 5.2 @PostConstruct
  • 5.3 @ModelAttribute
  • 六. 响应类注解
  • 6.1 @RequestBody
  • 6.2 @ResponseBody
  • 七. Cookie和Session
  • 7.1 Session
  • 7.1.1 注解的方式
  • 7.1.2 HttpServletRequest的方式
  • 7.2 Cookie
  • 7.2.1 注解的方式
  • 7.2.2 HttpServletResponse对象的方式
  • 八. 事务注解
  • 8.1 @EnableTransactionManagement
  • 8.2 @Transactional
  • 九. 扫描类注解
  • 9.1 @ComponentScan
  • 9.2 @MapperScan
  • 十. 异常注解
  • 10.1 @ControllerAdvice
  • 10.2 @ExceptionHandler
  • 十一. 其他
  • @EnableAsync
  • @Order
  • @Lazy
  • @Conditional
  • @DateTimeFormat


一. 容器标记类注解

1.1 @Controller

用来创建对象存放到Spring容器中,一般用在Controller层

import org.springframework.stereotype.Controller;

@Controller
public class GoodsController {

    // ...
}

1.2 @Service

用来创建对象存放到Spring容器中,一般用在Service层

import org.springframework.stereotype.Service;

@Service("serviceName")  // 给Bean取一个别名
public class GoodsService {
    
    // ...
}

1.3 @Repository

用来创建对象存放到Spring容器中,一般用在Dao层

import org.springframework.stereotype.Repository;

@Repository
public interface GoodsMapper {
    
    // ...
}

1.4 @Component

用来创建对象存放到Spring容器中,一般用在工具类上

@Component
public class IpUtil {
    
     // ...
}

1.6 @RestController

相当于@ResponseBody@Controller注解结合在一起使用

被修饰的类的所有方法都可以用流的方式把数据返回给前端

@RestController /* @Controller + @ResponseBody*/
public class HospitalController {

    // 注入Service服务对象
    @Autowired
    private HospitalService hospitalService;
	
    @RequestMapping(value = "findAllHospital",method = RequestMethod.GET)
    public  List<Hospital> findAllHospital(){
        List<Hospital> hospitalList= hospitalService.findAllHospital();
        // 由于@RestController注解中包含了@ResponseBody注解,因此可以把数据直接返回给前端
        return hospitalList;
    }

1.7 @Bean

@Bean是一个方法级别上的注解,用来将方法返回的对象添加到容器中

@Bean("queryRunner")  // 为要添加到容器中的对象取别名
public QueryRunner createQueryRunner(DataSource dataSource){
    QueryRunner queryRunner = new QueryRunner(dataSource);
    return queryRunner;
}

二. 注入类注解

2.1 @Autowired

将Spring容器中的对象注入.默认按照类型注入,如果类型有多个,则按照名称注入

@Controller
public class CSPLoginController extends BaseController {

    // 自动注入
    @Autowired
    private SystemComService commonService;
}

2.2 @Qualifier

必须与@Autowired结合使用,如果自动注入按照类型注入失败,则按照指定的名称注入

一个接口

public interface UserDao {
    void print();
}

实现类实现接口,一个接口被两个实现类实现

// 因为没有给要放入容器中的对象取别名,所以使用默认别名(第一个字母小写 => userDaoImpl)
@Repository
public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("UserDaoImpl的打印被执行了");
    }
}

@Repository
public class UserDaoImpl2 implements UserDao {

    @Override
    public void print() {
        System.out.println("UserDaoImpl2的打印被执行了");
    }
}

注入

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@Service
public class UserServiceImpl implements UserService {

    // 因为UserDao这个接口被两个实现类给实现了,我们用@Qualifier来明确到底用哪个实现类
    // userDaoImpl为UserDaoImpl默认的容器名称,默认为第一个字母小写
    @Qualifier("userDaoImpl")
    // 因为@Autowired默认按照类型注入,而实现了UserDao接口的Bean有多个
    // 如果不配合@Qualifier使用的话,会报错
    @Autowired  
    private UserDao userDao;

    @Override
    public void print() {
        userDao.print();
    }
}

2.3 @Resource

默认按照名称注入,没有名称没有找到,按照类型注入.其作用相当于@Qualifier和@Autowired的结合

此注解是由JDK提供的

import javax.annotation.Resource;

@Service
public class UserServiceImpl implements UserService {

    // 参考@Qualifier的例子
    // 虽然UserDao接口被多个类实现,但是由于@Resource指定了Bean的名称,因此会注入成功
    @Resource(name = "userDaoImpl")
    private UserDao userDao;

    @Override
    public void print() {
        userDao.print();
    }
}

2.5 @Primary

  • 当一个接口被多个类给实现的情况下,给实现类添加此注解,默认就注入此实现类
  • 此类作用于方法上

接口

public interface Singer {
    String sing(String lyrics);
}

实现类

import org.springframework.context.annotation.Primary;

@Component
public class MetalSinger implements Singer{

    @Override
    public String sing(String lyrics) {
        return "I am singing with DIO voice: " + lyrics;
    }
}

@Primary
@Component
public class OperaSinger implements Singer {
    @Override
    public String sing(String lyrics) {
        return "I am singing in Bocelli voice: " + lyrics;
    }
}

注入

@Component
public class SingerService {

    // 虽然Singer接口被多个实现类所实现,但是因为其中OperaSinger实现类添加了@Primary注解
    // 因此此实现类对象会被优先注入
    @Autowired
    private Singer singer;

    @Qualifier("opreaSinger")
    public String sing(){
        return singer.sing("song lyrics");
    }
}

2.6 @Import


只能作用在类上,常用于将第三方包的对象放入Spring容器中

2.6.1 class数组的方式

新建一个普通的类

public class TestA {

    public void fun(String str) {
        System.out.println(str);
    }

    public void printName() {
        System.out.println("类名 :" 
                           + Thread.currentThread().getStackTrace()[1].getClassName());
    }
}

使用@Import注解将普通类导入到配置类中

@Import({TestA.class})
@Configuration  // 为了让Spring扫描到这个类
public class ImportConfig {
    
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ApplicationMain.class)
public class ImportAnnotionTest {

    // 虽然TestA原本只是一个普通类,但是通过@Import注解导入到配置类中,所在可以在此处注入
    @Autowired  
    private TestA testA;

    @Test
    public void TestA() {
        testA.printName();
    }
}

2.6.2 实现ImportSelector接口

新建普通类

public class TestC {
    public void fun(String str) {
        System.out.println(str);
    }

    public void printName() {
        System.out.println("类名 :" + 
                           Thread.currentThread().getStackTrace()[1].getClassName());
    }
}

新建一个类实现ImportSelector接口

public class SelfImportSelector implements ImportSelector {
    
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 返回值是一个数组,数组内的元素是普通类的全限定类名
        // 不能返回null,否则会报空指针异常
        return new String[]{"com.test.importdemo.TestC"};
    }
}

配置文件类中导入接口的实现类

@Import({SelfImportSelector.class})
@Configuration
public class ImportConfig {
    
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ApplicationMain.class)
public class ImportAnnotionTest {

    @Autowired
    private TestC testC;

    @Test
    public void TestC() {
        testC.printName();
    }
}

2.6.3 实现ImportBeanDefinitionRegistrar 接口

新建普通类

public class TestD {
    public void fun(String str) {
        System.out.println(str);
    }

    public void printName() {
        System.out.println("类名 :" + 
                           Thread.currentThread().getStackTrace()[1].getClassName());
    }
}

实现ImportBeanDefinitionRegistrar 接口

public class SelfImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(
        AnnotationMetadata importingClassMetadata, 
        BeanDefinitionRegistry registry)
    {
        RootBeanDefinition root = new RootBeanDefinition(TestD.class);
        registry.registerBeanDefinition("testD", root);
    }
}

配置文件类中导入接口的实现类

@Import({SelfImportBeanDefinitionRegistrar.class})
@Configuration
public class ImportConfig {
    
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ApplicationMain.class)
public class ImportAnnotionTest {

    @Autowired
    private TestC testD;

    @Test
    public void TestC() {
        testD.printName();
    }
}

三. 配置文件类注解

3.1 @Configuration

声明当前类为配置类,此注解内部组合了@Component注解,可以将配置类注入到容器中

import org.springframework.context.annotation.Configuration;

@Configuration
public class DbSourceConfig {
    
    @Value("${spring.test.url}")
    private String url;
}

3.2 @Value


  • 用在全局变量上,把外部的配置文件的配置信息注入到类的属性上
  • 配合EL表达式,对配置文件读取到的数据进行处理
  • ${}用于加载配置文件中的信息
  • #{}用于把内容赋值给属性
  • ${}#{}可以混合使用

配置文件application.properties

spring.test.url=www.baidu.com
test.array1=aaa,bbb,ccc

一个Bean

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

// 将Item放入容器,并取别名
@Component("itemBean")
public class Item {

	@Value("99")
	private int qtyOnHand;
	
	public int getQtyOnHand() {
		return qtyOnHand;
	}

	public void setQtyOnHand(int qtyOnHand) {
		this.qtyOnHand = qtyOnHand;
	}
}

注入

import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;

@Configuration
public class DbSourceConfig {
    
    // 最常见的使用方法,使用${}的方式从配置文件中读取配置信息注入到属性中
    @Value("${spring.test.url}")
    private String url;
    
    // 可以配合EL表达式使用,对从配置文件获取到的数据进行处理
    @Value("#{'${test.array1:}'.empty ? null : '${test.array1:}'.split(',')}")
    private List<String> testList1;
    
    // 调用random方法获取返回值
	@Value("#{T(java.lang.Math).random()}")
	private double ramdom;
    
    // 注入简单值,输出num为5
	@Value("#{5}")
	private Integer num;
    
    // 支持基本运算
    @Value("#{1 + 1}") 
	private double testAdd;  // 2
    
    // 支持比较运算符
    @Value("#{1 >= 1}")
    private boolean testGreaterThanOrEqual;  // true
    
    // 将容器中的Bean属性获取到,并进行处理
    @Value("#{itemBean.qtyOnHand < 100 ? true : false}")
	private boolean warning;  // true
    
}

3.3 @ConfigurationProperties

通过指定一个前缀来将配置文件中的数据注入到配置类中的属性上

注意:

  • 需要有配置类的属性需要有set方法,否则无法绑定
  • 如果没有使用@Component等容器注解将配置类注入到容器中,需要在使用配置类的地方使用@EnableConfigurationProperties注解来手动开启配置

配置文件

spring.datasource.url=jdbc:mysql://127.0.0.1:8888/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

配置方法1

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "spring.datasource")
@Component  // 将配置类注入到Spring容器中
public class DatasourcePro {

    private String url;
    private String username;
    private String password;
    // 配置文件中是driver-class-name,我们可以直接使用驼峰的形式
    private String driverClassName;
    private String type;

    // 此处省略了Get和Set方法,必须要有Set方法否则无法将配置文件中的数据绑定到配置类的属性中
}

配置方式2

import org.springframework.boot.context.properties.ConfigurationProperties;

// 此处只有这一个注解,并没有@Component等容器注解
@ConfigurationProperties(prefix = "spring.datasource")
public class DatasourcePro {

    private String url;
    private String username;
    private String password;
    // 配置文件中是driver-class-name,我们可以直接使用驼峰的形式
    private String driverClassName;
    private String type;

    // 此处省略了Get和Set方法,必须要有Set方法否则无法将配置文件中的数据绑定到配置类的属性中
}
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@Component
// 通过此注解对DatasourcePro配置类实例化
@EnableConfigurationProperties(DatasourcePro.class)  
public class GetConfigMessage {

    @Autowired
    private DatasourcePro configInfo;
    
    // 使用configInfo对象来获取配置文件的信息
}

3.4 Environment对象

配置文件

# 图片的后缀列表
spring.suffixList=jpeg,jpg,png,gif,bmp

使用Environment对象获取配置文件信息

@Service
public class UploadService {

    // 注意,不能添加无参数的构造方法,否则无法从配置文件中读取配置

    // 注入配置文件对象类
    @Autowired
    private Environment env;

    private Boolean fileCheck() {
		
        // 通过Environment对象获取配置文件的信息
        String prop = env.getProperty("spring.suffixList");
        String[] split = prop.split(",");
        List<String> suffixList = Arrays.asList(split);
        
        // ...
    }
}

3.5 @PropertySource

  • 如果将所有的配置信息都写在一个配置文件中会让配置文件臃肿难以维护.
  • 可以将一个文件拆分为多个,使用 @PropertySource 注解加载指定的配置文件.

存放在resources文件夹根目录下的jdbc.properties配置文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_test
jdbc.user=root
jdbc.password=mysql

配置文件信息注入

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

// 将配置类放入Spring容器中
@Configuration 
@PropertySource("jdbc.properties")  // 引入外部的配置文件
public class JDBCConfiguration {

    // 把外部的配置文件的值给导入到对象中去
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driver}")
    private String driverClass;
    @Value("${jdbc.user}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
}

3.6 @SpringBootConfiguration


四. URL处理类注解

4.1 @RequestMapping

@Controller
@RequestMapping("/test")  // 可以放在类上,也可以放在方法上,放在类上用来窄化路径
public class TestController {
	
    // 如果不指定方法的话,默认是Get方法
    @RequestMapping(value = "/hello", method = RequestMethod.POST)
    public String hello(){

        return "show";
    }
    
    @RequestMapping(
        value = "/test", 
        method = RequestMethod.POST,
        // 要求URL中必须有name和age>20这两个名称(*age>20只是一个名称,并不能真的约束age的值)
        // 要求URL中不能包含a这个名称
        params = {"name","age>20","!a"}
    )
    public String hello(){

        return "show";
    }
}

4.2 @GetMapping

@GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写

4.3 @PostMapping

@PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写

同理,还有@PutMapping、@DeleteMapping等注解

4.4 @RequestParam

import org.springframework.web.bind.annotation.RequestParam;

@RequestMapping(value = "/param2")
public String testParams(
    @RequestParam(
        // 前端传入的值
        value = "username",
        // 指定此参数不是必须要传的
        required = false,
        // 如果前端没有传值的话,用我们自己的默认值
        defaultValue = "rose"
    ) 
    // 由于前后端的命名方式不同,因此通过@RequestParam注解进行转化
    String name
){
    System.out.println(name);
    return "show";
}

4.5 @PathVariable

常用于获取restful风格的请求路径中URL中的值

// URL中的包含的id通过@PathVariable注解获取出来
@RequestMapping(value = "/operate/{id}",method = RequestMethod.GET)
public String findById(@PathVariable("id") Integer id){
    System.out.println("findById:" + id);
    return "show";
}

五. 初始化类

5.1 @InitBinder


简介

@InitBinder作用于@Controller中的方法,表示为当前控制器注册一个属性编辑器,对WebDataBinder进行初始化,且只对当前的Controller有效。

执行时机

@InitBinder注解被解析的时机,是其所标注的方法,在该方法被请求执行之前。同时@InitBinder标注的方法是可以多次执行的,也就是说来一次请求就执行一次@InitBinder解析。

执行原理

当某个Controller上的第一次请求,由SpringMVC前端控制器匹配到该Controller之后,根据Controller的 class 类型来查找所有标注了@InitBinder注解的方法,并且存入RequestMappingHandlerAdapter里的 initBinderCache 缓存中。等下一次请求执行对应业务方法之前,会先走initBinderCache缓存,而不用再去解析@InitBinder。

应用场景

常用于数据绑定和数据转换

场景1,使用系统默认的属性编辑器

@RequestMapping("/myInitBinder0954")
@Controller
public class MyInitBinderController {

	// 注册将字符串转换为Date的属性编辑器,该编辑器仅仅对当前controller有效
	@InitBinder
	public void initBinderXXX(WebDataBinder binder) {
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		CustomDateEditor dateEditor = new CustomDateEditor(df, true);
		binder.registerCustomEditor(Date.class, dateEditor);
	}
    
    // 前端访问URL
	// http://localhost:8080/myInitBinder0954/test?date=2020-09-03%2010:17:17
	@RequestMapping(value = "/test", method = RequestMethod.GET)
	@ResponseBody
	public String testFormatData(Date date) {
        
        // 将URL中日期字符串转换为Date类型
		Map<String, Object> map = new HashMap<>();
		map.put("date", date);
		return map.toString();
	}
}

场景2,使用自定义的属性编辑器

自定义属性编辑器

import java.beans.PropertyEditorSupport;

public class StringToListPropertyEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        String[] resultArr = null;
        if (!StringUtils.isEmpty(text)) {
            // 将字符串以"_"进行分隔
            resultArr = text.split("_");
        }
        this.setValue(resultArr);
    }
}
@RequestMapping("/myStringToList")
@Controller
public class StringToListController {

	@InitBinder
	public void myStringToListBinder(WebDataBinder dataBinder) {
		dataBinder.registerCustomEditor(
            String[].class, 
            // 使用我们自定义的属性编辑器
            new StringToListPropertyEditor()
        );
	}

	@RequestMapping(value = "/test", method = RequestMethod.GET)
	@ResponseBody
	public String myStringToListTest(String[] strToListArr) {
        
		String result = "_分割字符串转String[]不成功!";
		if (strToListArr != null && strToListArr.length > 0) {
			result = Arrays.asList(strToListArr).toString();
		}
		return result;
	}
}

5.2 @PostConstruct

在需要初始化的方法上增加@PostConstruct注解,这样就有初始化的能力。

import javax.annotation.PostConstruct;
import org.springframework.stereotype.Service;

@Service
public class AService {

    @PostConstruct
    public void init() {
        System.out.println("===初始化===");
    }
}

5.3 @ModelAttribute


定义一个基础的控制类

public class BaseController {
    
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    protected HttpSession session;
	
    // 每一个继承了BaseController的子Controller都会先执行下面的方法
    @ModelAttribute
    public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {

        this.request = request;
        this.response = response;
        this.session = request.getSession();
    }
}

子类控制类

import org.apache.commons.lang3.StringUtils;

@Controller
public class CmsPagePreviewController extends BaseController {

    @Autowired
    private PageService pageService;

    // 页面预览
    @RequestMapping(value="/cms/preview/{pageId}",method = RequestMethod.GET)
    public void preview(@PathVariable("pageId")String pageId){
        
        // response 是 父类BaseController 中封装的对象
        ServletOutputStream outputStream = response.getOutputStream();
        response.setHeader("Content-type","text/html;charset=utf-8");
    }
}

六. 响应类注解

6.1 @RequestBody

@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的),一般会用一个对象来封装数据

@RequestMapping(value = "/dologin", method = RequestMethod.POST)
@ResponseBody
public void login(@RequestBody LoginUser userInfo) {
    
    // ...
}


6.2 @ResponseBody


  • @ResponseBody的作用其实是将java对象转为json格式的数据。
  • @responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
@RequestMapping("/testResponseBody")
@ResponseBody
public List<User> testResponseBody(){
    
    List<User> userList = new ArrayList<>();
    // 新建一个对象放入数据
    User user = new User();
    user.setUsername("zhangsan");
    user.setSex("男");
    user.setId(2);
    
    // 新建一个对象放入数据
    User user1 = new User();
    user1.setUsername("zhangsan1");
    user1.setSex("女");
    user1.setId(1);
    
    userList.add(user);
    userList.add(user1);

    // 把封装好的数据传递给前端
    return userList;
}

七. Cookie和Session


7.1 Session

7.1.1 注解的方式


  • 若希望在多个请求之间共用数据,则可以在控制器类上标注一个 @SessionAttributes,配置需要在session中存放的数据范围,Spring MVC将存放在model中对应的数据暂存到HttpSession 中。
  • @SessionAttributes需要清除时,使用SessionStatus.setComplete();来清除。

注意session.removeAttribute只清除@SessionAttributes的session,不会清除HttpSession的数据

@SessionAttributes

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;

import java.util.Date;
import java.util.Map;

@Controller
@RequestMapping("/test")
// 用来向session中存放数据,在session中可以存储这两个变量名
@SessionAttributes({"username","password"})  
public class TestController {

    // 把用户名和密码存入到Session范围内
    @RequestMapping("/testPut")
    public void testPut(Model model){
        // 存放session对象的时候,用Model和ModelMap来存放对象都可以
        model.addAttribute("username","zhangsan");
        model.addAttribute("password","123456");
    }

    // 获取session范围内的对象
    @RequestMapping("/testGet")
    public void testGet(ModelMap modelMap){
        // 获取session对象的时候,要用modelMap来获取
        Object username = modelMap.get("username");
        System.out.println(username);  // zhangsan
        Object password = modelMap.get("password");
        System.out.println(password);  // 123456
    }

    // 清空session中的数据
    @RequestMapping("/testClear")
    public void testClear(SessionStatus sessionStatus){
        sessionStatus.setComplete();
    }
}
@SessionAttributes("user")
public class UserController { 

    @ModelAttribute("user")
    publicUser getUser(){
        Useruser = new User();
        User.setUserId("1001");
        returnuser;
    }

    @RequestMapping("/handle71")
    public String handle71(@ModelAttribute("user") User user) { 
        user.setName("John");
        return “redirect:/user/handle71.html”;
    } 

    @RequestMapping(value= "/handle72") 
    public String handle72(ModelMapmodelMap, SessionStatus sessionStatus) { 
        User user = (User)modelMap.get("user");
        If(user != null){
            user.setName("jetty");
            sessionStatus.setComplete();

        }
        return "user/showUser"; 
    } 

    @RequestMapping("/tologout")
    public String tologout(HttpSession session, SessionStatus sessionStatus) {
        session.removeAttribute("user");
        session.removeAttribute("date");
        System.out.println("logout:" + session.getAttribute("user"));
        
        // 一定要通过这种方式清除@SessionAttributes中存放的数据
        sessionStatus.setComplete(); 
        
        return "redirect:/view/index";
    }
}

7.1.2 HttpServletRequest的方式

@Component
public class Test {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private HttpServletResponse response;

    @Override
    public void test() {

        // 获取session对象
        HttpSession session = request.getSession();

        // 将数据放入session
        session.setAttribute("shainNo", "XXX");
        session.setAttribute("shainMei", "XXX");

        // 从session中获取数据
        session.getAttribute("shainMei");
        
        // 从session中清除数据
        session.removeAttribute("shainMei");
    }
}

7.2 Cookie


7.2.1 注解的方式

@CookieValue用来获取Cookie中的值

@RestController
public class HelloController {

    @RequestMapping("/hello2")
    public String hello2(HttpServletResponse response){
        
        // 自己新建一个cookie
        Cookie cookie = new Cookie("name","瓜田李下");
        response.addCookie(cookie);

        return "success2";
    }
	
    // 通过@CookieValue的方式获取cookie中的值
    @RequestMapping("/hello3")
    public String hello3(HttpServletRequest request,@CookieValue("name") String name){
        
        // 打印从通过@CookieValue注解从cookie中获取到的值
        System.out.println(name);  // 瓜田李下
		
        // 普通的方式获取cookie中的值
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies){
            String value = cookie.getName() + "  " + cookie.getValue();
            System.out.println(value);  // name  瓜田李下
        }

        return "success3";
    }
}

7.2.2 HttpServletResponse对象的方式

@Component
public class Test {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private HttpServletResponse response;

    @Override
    public void test() {
       
        // Cooikesの格納値を設定する
        Cookie nameCookie = new Cookie("name", "zhangsan");
        Cookie pswCookie = new Cookie("pwd", "123");
		
        // 设置cookie的超时时间
        if ("XXX") {
            nameCookie.setMaxAge(0);
            pswCookie.setMaxAge(0);
            remberMeCookie.setMaxAge(0);
        } else {
            nameCookie.setMaxAge(7 * 24 * 60 * 60);
            pswCookie.setMaxAge(7 * 24 * 60 * 60);
        }
        
        // 将cookie添加到响应中
        response.addCookie(nameCookie);
        response.addCookie(pswCookie);
    }
}

cookie的获取

public static String getCookieValue(HttpServletRequest request, String name) {
    
    // 获取本次请求中所有的cookie
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            // 获取cookie的key
            String cookieName = cookie.getName();
            if (cookieName.equals(name)) {
                // 获取cookie的值
                return cookie.getValue();
            }
        }
    }
    return null;
}

八. 事务注解

8.1 @EnableTransactionManagement

  • 为工程开启事务
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement  // 使用此注解为Spring Boot项目开启事务配置
public class SpringbootApplication {

    public static void main(String[] args) {
        try {
            SpringApplication.run(SpringbootApplication.class, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

8.2 @Transactional

  • 为方法开启事务
import org.springframework.transaction.annotation.Transactional;

// 使用此注解为update方法开启事务
@Transactional(rollbackFor = Exception.class)
public int update(CSPMailAddresHenkoForm form, LoginUser user) {
	// ...
}

九. 扫描类注解


9.1 @ComponentScan

@ComponentScan做的事情就是告诉Spring从哪里找到bean

SpringbootApplication启动类会自动扫描与其同级别的目录下的类上是否标记了@Component,@Controller等注解.如果被标记则添加到容器中.如果启动类外层还有一层文件夹或者有些类不和启动类在同一个级别的文件下的话,就需要使用@ComponentScan注解,手动指定要扫描的包的位置

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement
// 扫描该包下面的组件,配置了
@ComponentScan({"com.csp.common.security.springsecurity"})  
public class SpringbootApplication {
    
    public static void main(String[] args) {
        try {
            SpringApplication.run(SpringbootApplication.class, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

9.2 @MapperScan

  • 在Springboot启动类上面添加
  • 指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
  • 省去了在每一个接口上手动添加@Mapper注解的麻烦
import org.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@EnableTransactionManagement
@MapperScan({"com.csp.common.db.dao", "com.csp.business.dao"})
public class SpringbootApplication {

    public static void main(String[] args) {
        try {
            SpringApplication.run(SpringbootApplication.class, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

十. 异常注解


10.1 @ControllerAdvice

最常见的使用场景就是异常处理

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

// 用来实现全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {

    // 此注解用来指明具体要处理的异常类型
    @ExceptionHandler(value = {Exception.class})
	@ResponseBody
    public void exceptionHandler(Exception exception) {
		
        // ...
    }
	
    // 此注解用来指明具体要处理的异常类型
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public void handleNotValidException(MethodArgumentNotValidException ex) {
    	
        // ...
    }
    
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public void handleBindException(BindException ex) {
        
        // ...
    }
}

10.2 @ExceptionHandler

此注解用来指明具体要处理的异常类型

具体使用例子参考@ControllerAdvice

十一. 其他

@EnableAsync

@Order


  • 定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,Bean的加载顺序不受@Order或Ordered接口的影响
  • 可以和CommandLineRunner接口配合使用,通过@Order注解指定实现类的加载顺序
  • 值越小,加载的优先级就越高
@Order(value=3)
@Component
class ApplicationStartupRunnerOne implements CommandLineRunner {
    
    @Override
    public void run(String... args) throws Exception {
        
        System.out.println("ApplicationStartupRunnerOne run method Started !!");
    }
}
 
@Order(value=2)
@Component
class ApplicationStartupRunnerTwo implements CommandLineRunner {
 
    @Override
    public void run(String... args) throws Exception {
        
        System.out.println("ApplicationStartupRunnerTwo run method Started !!");
    }
}

// 执行之后的打印顺序
ApplicationStartupRunnerTwo run method Started !!
ApplicationStartupRunnerOne run method Started !!

@Lazy


  • 减少springIOC容器启动的加载时间,只有调用某个bean的时候才会去初始化
  • 可以用来解除循环依赖注入的问题

@Conditional


  • 通过条件来控制bean的注册,只有满足相应的条件,类对象才会被放入Spring容器中

@DateTimeFormat