枚举类和反射:
使用枚举实现单例模式,防止反射攻击私有构造器
public enum EnumSingleton{ INSTANCE; public EnumSingleton getInstance(){ return INSTANCE; } } public static void main(String[] args) { //通过反射获取枚举类 //1、获取枚举类的类型 Class<EnumSingleton> calzz =EnumSingleton.class; Constructor<EnumSingleton> constructor = calzz.getDeclaredConstructor(String.class,int.class); //爆破 Constructor.setAccessible(true); EnumSingleton enumSingleton = constructor.newInstance(); System.out.print("enumSingleton" + enumSingleton);//会报异常 }
请求响应
数组参数:
请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数
@RequestMapping("/arrayParam") public String arrayParam(String[] hobby){ System.out.print(Array.toString(hobby)); return "OK"; }
集合参数:
请求参数名与形参集合名称相同且请求参数为多个,@RequestParam 绑定参数关系
@RequestMapping("/listParam") public String listParam(@RequestParam List<String> hobby){ System.out.print(hobby); return "OK"; }
日期参数:
使用 @DateTimeFormat 注解完成日期参数格式转换
@RequestMapping("/dateParam") public String dataParam(@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")LocalDateTime updateTim return "OK";
Json 参数:
JSON 数据键名与形参对象属性名相同,定义 PIJO 类型形参即可接收参数,需要使用 @RequestBody 标识
public class User{ private String name; private Integer age; private Address address; } public class Address{ private String province; private String city; } @RequestMapping("/jsonParam") public String jsonParam(@RequestBody User user){ System.out.print(user); return "OK"; }
路径参数:
通过请求 URL 直接传递参数,使用 {…} 来表示该路径参数,需要使用 @PathVariable 获取路径参数
@RequestMapping("/Path/{id}") public String pathParam(@PathVariable Integer id){ System.out.print(id); return "OK"; } //多个路径参数 @RequestMapping("/Path/{id}/{name}") public String pathParam(@PathVariable Integer id,@PathVariable String name){ System.out.print(id + ":" + name); return "OK"; }
请求响应总结:
- 简单参数
定义方法形参,请求参数名与形参变量名一致
如果不一致,通过 @RequestParam 手动映射 -
实体参数
请求参数名与实体对象的属性名一致,就会自动接收封装 -
数组集合参数
数组:请求参数名与数组名一致,直接封装
集合:请求参数名与集合名一致,@RequestParam 绑定参数关系 -
日期参数
@DateTimeFormat -
JSON 参数
@RequestBody -
路径参数
@PathVariable
@ResponseBody:
- 类型:方法注释、类注释
- 位置:Controller 方法上 / 类上
- 作用:将方法返回值直接响应,如果返回值类型是 实体对象 / 集合,将会转换为 JSON 格式响应
- 说明 @RestController=@Controller+@ResponseBody
Result:
统一响应结果
public class Result{ //响应码,1代表成功;0代表失败 private Integer code; //提⽰信息 private String msg; //返回数据 private Object data; //…… }
响应的数据:
{ "code":1, "msg":"操作成功" "data": }
例:
获取员工数据,返回统一响应结果,在页面渲染展示
加载并解析 emp.xml 文件中的数据,完成数据处理,并在页面展示
注意:Springboot 项目的静态资源 (html,css,js 等前端资源) 默认存放目录为:
classpath:/static、classpath:/public、classpath:/resources
步骤:
- 在 pom.xml 文件中引入 dom4j 的依赖,用于解析 XML 文件
<dependency> <groupID>org.dom4j</groupID> <artifactID>dom4j</artifactID> <version>2.1.3</version> </dependency>
- 引入资料中提供的解析 XML 的工具类 XMLParserUtils、对应的实体类 Emp、XML 文件 emp.XML
- 引入静态页面文件,放在 resource 下的 static 目录下
- 编写 Controller 程序,处理请求,响应数据
emp.xml
<emps> <emp> <name>⾦⽑狮王</name> <age>55</age> <image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/1.jpg</image> <!-- 1: 男, 2: ⼥ --> <gender>1</gender> <!-- 1: 讲师, 2: 班主任 , 3: 就业指导 --> <job>1</job> </emp> <emp> <name>⽩眉鹰王</name> <age>65</age> <image>https://web-framework.oss-cn-hangzhou.aliyuncs.com/web/2.jpg</image> <gender>1</gender> <job>1</job> </emp> </emps> @RestController public class EmpController { @RequestMapping("/listEmp") public Result list(){ //1、加载并解析emp.xml //String file = "D:\\Code-Project\\project_practice\\springBoot02\\src\\main\\resources"; String file = this.getClass().getClassLoader().getResource("emp.xml").getFile(); System.out.println(file); List<Emp> empList = XmlParserUtils.parse(file, Emp.class); //2、对数据进⾏转换处理 - gender,job //遍历 empList.stream().forEach(emp -> { //处理gender 1:男;2:⼥ String gender = emp.getGender(); if ("1".equals(gender)){ emp.setGender("男"); } else if ("2".equals((gender))) { emp.setGender("⼥"); } //处理job 1:讲师;2:班主任;3:就业指导 String job = emp.getJob(); if ("1".equals(job)){ emp.setJob("讲师"); } else if ("2".equals((job))) { emp.setJob("班主任"); }else if ("3".equals((job))) { emp.setJob("就业指导"); } }); //3、响应数据 return Result.success(empList); } }
分层解耦:
三层架构:Controller (接受请求,响应数据)、Service (逻辑处理)、Dao (数据访问)
- Controller:控制层,接受前端发送的请求,对请求进行处理,并响应数据
- Service:业务逻辑层,处理具体的业务逻辑
- Dao:数据访问层 (Data Access Object) 持久层,负责数据访问操作,包括数据的增、删、改、查
controller:
com.itheima.controller.EmpController @RestController public class EmpController { private EmpService empService = new EmpServiceA(); @RequestMapping("/listEmp") public Result list(){ //调⽤service,获取数据 List<Emp> empList = empService.listEmp(); //3、响应数据 return Result.success(empList); } }
service:
com.itheima.service.EmpService: public interface EmpService { //获取员工列表 public List<Emp> listEmp(); } com.itheima.service.impl.EmpServiceA: public class EmpServiceA implements EmpService { private EmpDao empDao = new EmpDaoA(); @Override public List<Emp> listEmp() { //调用Dao,获取数据 List<Emp> empList = empDao.listEmp(); //2、对数据进行转换处理 - gender,job //遍历 empList.stream().forEach(emp -> { //处理gender 1:男;2:女 String gender = emp.getGender(); if ("1".equals(gender)){ emp.setGender("男"); } else if ("2".equals((gender))) { emp.setGender("女"); } //处理job 1:讲师;2:班主任;3:就业指导 String job = emp.getJob(); if ("1".equals(job)){ emp.setJob("讲师"); } else if ("2".equals((job))) { emp.setJob("班主任"); }else if ("3".equals((job))) { emp.setJob("就业指导"); } }); return empList; } }
dao:
com.itheima.dao.EmpDao: public interface EmpDao { //获取员工列表数据 public List<Emp> listEmp(); } com.itheima.dao.impl.EmpDaoA: public class EmpDaoA implements EmpDao { @Override public List<Emp> listEmp() { //1、加载并解析emp.xml //String file = "D:\\Code-Project\\project_practice\\springBoot02\\src\\main\\resources"; String file = this.getClass().getClassLoader().getResource("emp.xml").getFile(); System.out.println(file); List<Emp> empList = XmlParserUtils.parse(file, Emp.class); return empList; } }
分层解耦:
- 内聚:软件中各个功能模块内部的功能联系
- 耦合:衡量软件中各个层 / 模块之间的依赖、关联的程度
- 软件设计原则:高内聚低耦合
- 控制反转:Inversion Of Control,简称 IOC。对象的创建控制权由程序自身转移到外部 (容器),这种思想成为控制反转
- 依赖注入::Dependency Injection,简称 DI。容器为应用程序提供运行时所依赖的资源,称之为依赖注入
- Bean 对象:IOC 容器中创建、管理的对象,称之为 bean
IOC&DI 入门:
- @Component:将当前类交给 IOC 容器管理,成为 IOC 容器中的 bean
- @Autowired:运行时,IOC 容器会提供该类型的 bean 对象,并赋值给该变量 —— 依赖注入
- Service 层 及 Dao 层 的实现类,交给 IOC 容器管理
- 为 Controller 及 Service 注入运行时依赖的对象
- 运行测试
controller:
@Component @RestController public class EmpController { @Autowired private EmpService empService ; }
service:
@Component public class EmpServiceA implements EmpService { @Autowired private EmpDao empDao; …… }
dao:
@Component public class EmpDaoA implements EmpDao { }
IOC 详解:
Bean 的声明:
要把某个对象交给 IOC 容器管理,需要在对应的类上加如下注解:
注释 | 说明 | 位置 |
---|---|---|
@Component | 声明 bean 的基础注解 | 不属于以下三类时,用此注解 |
@Controller | @Component 的衍生注解 | 标注在控制器上 |
@Service | @Component 的衍生注解 | 标注在业务上 |
@Repository | @Component 的衍生注解 | 标注在数据访问类上 (由于与 mybatis 整合,用的少) |
注意事项:
@RestController=@Controller+@ResponseBody
,所以控制层不用再额外加 @Component 或者 @Controller- 声明 bean 的时候,可以通过 value 属性指定 bean 的名字,如果没有指定,默认为首字母小写的类名
@Component(value = "daoA")[value可以省略]
- 使用以上四个注解都可以声明 bean,但是在 springboot 集成 web 开发中,声明控制器 bean 只能用 @Controller
Bean 组件扫描:
- 前面声明的四大注解,想要生效,还需要被组件扫描注解 @ComponentScan 扫描
- @ComponentScan 注解虽然没有显示配置,但是实际上已经包含了启动类声明注解 @SpringBootApplication 中,默认扫描的范围是启动类所在包以及其子包
DI 详解:
@Autowired 注解,默认是按照类型进行,如果存在多个相同类型的 bean,将会报错
可以通过以下方法解决:
- @Primary:设置 bean 的优先级,想让哪个 bean 生效,就在哪个 bean 上再加 @Primary 注解
@Primary @Service public class EmpServiceA implements EmpService{}
- @Qualifier:在 @Autowired 上再加 @Qualifier 指定 bean 的名字
@Qualifier("empServiceA") @Autowired private EmpService empService;
- @Resource:不使用 @Autowired,直接用 @Resource 按名称注入 (@Autowired 按类型注入)
@Resource(name = "empServiceA") private EmpService empService;
@Resource 与 @Autowired 的区别:
- @Autowired 是 spring 框架提供的注解,而 @Resource 是 JDK 提供的注解
- @Autowired 默认是按照类型注入,而 @Resource 默认是按名称注入