枚举类和反射:
使用枚举实现单例模式,防止反射攻击私有构造器
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 updateTime)
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
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>
步骤:
- 在 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程序,处理请求,响应数据
@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 默认是按名称注入