spring boot
配置文件:
格式一:
application.properties
例如:添加全局訪問路徑和修改 Tomcat 的端口號
server.context-path=/demo
server.port=8081
格式二:
-
系統屬性
application.yml例如:添加全局訪問路徑 和 修改 Tomcat 的端口號
server: context-path: /demo port: 8081 -
自定義屬性:
application.ymlage: 18 # 自定義屬性 name: inke # 自定義屬性 content: "name:${name},age:${age}" #配置引用配置在代碼中引用
HelloController.java@Value("${age}") private Integer age;//@value可以獲取application.yml配置的值 @RestController public class HelloController { } -
類和屬性關聯
application.ymlperson: age: 18 # 自定義屬性 name: inke # 自定義屬性Person.java@Component @ConfigurationProperties(prefix = "person") public class Person { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }在代碼中引用
HelloController.java@RestController public class HelloController { // @Value("${age}") // private Integer age; // // @Value("${content}") // private String content; @Autowired private Person person; @RequestMapping(value = "/hello") public String sayHello() { return "hello world name:" + person.getName() + " , age:" + person.getAge(); } }
多個配置文件切換
application.yml 通過 active 指定的屬性的環(huán)境:dev 還是 prod
spring:
profiles:
active: prod
application-dev.yml
person:
age: 18 # 自定義屬性
name: dev001 # 自定義屬性
application-prod.yml
person:
age: 18 # 自定義屬性
name: prod001 # 自定義屬性
啟動的時候,會根據 active 指定的環(huán)境屬性文件進行加載。
Controller
示例:
HelloController
package com.example;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Value("${age}")
private Integer age;//@value可以獲取application.yml配置的值
@RequestMapping(value = "/hello")
public String sayHello() {
return "hello world age:" + age;
}
}
application.yml
age: 18
常用注解
@RestController = @Controller + @ResponseBody
@Controller需要返回 template 模版,類似于 Django 的模板。
建議使用:@RestController
映射多個路徑
- 單個映射:
@RequestMapping(value = "/hello")
@RequestMapping(value = "/hello")
public String sayHello() {
return "hello world name:" + person.getName() + " , age:" + person.getAge();
}
- 多個映射:
@RequestMapping(value = {"hello", "hi"})
@RequestMapping(value = {"hello", "hi"})
public String sayHello() {
return "hello world name:" + person.getName() + " , age:" + person.getAge();
}
- 整個 controller 增加映射,在類上增加:
@RequestMapping(value = "/demo")
@RestController
@RequestMapping(value = "/demo")
public class HelloController {
@Autowired
private Person person;
@RequestMapping(value = {"hello", "hi"})
public String sayHello() {
return "hello world name:" + person.getName() + " , age:" + person.getAge();
}
}
訪問方式:
method = RequestMethod.GETmethod = RequestMethod.POST- ...
- 簡便方式:
@GetMapping(value = "hello")@PostMapping(value = "hello")
@RestController
@RequestMapping(value = "/demo")
public class HelloController {
@Autowired
private Person person;
@RequestMapping(value = {"hello", "hi"}, method = RequestMethod.GET)
//@GetMapping(value = "hello")
public String sayHello() {
return "hello world name:" + person.getName() + " , age:" + person.getAge();
}
}
注意:什么都不寫,默認是 get 和 post 都可以訪問,但是不建議這樣做,需要明確指定訪問方式。
獲取訪問參數
-
獲取
GET的URL的參數和POST的 請求body參數- 字段field映射
@RequestMapping(value = "hello", method = RequestMethod.GET) public String sayHello(@RequestParam(value = "id", required = false, defaultValue = "0") Integer id) { return "id:" + id; }- 實體 model 映射
@PostMapping(value = "/addPerson") public Person addPerson(Person person) { return personRespository.save(person); }
- 獲取 restfully 參數
@RequestMapping(value = "hello/{id}", method = RequestMethod.GET)
public String sayHello(@PathVariable("id") Integer id) {
return "id:" + id;
}
數據庫
-
準備工作,加入數據庫的配置和依賴
pom.xml
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>application.yml
spring: profiles: active: prod datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot username: root password: root jpa: hibernate: ddl-auto: create show-sql: truePerson.java
@Entity public class Person { @Id @GeneratedValue private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }創(chuàng)建接口繼承JpaRepository,泛型使用的是
public interface PersonRespository extends JpaRepository<Person, Integer> { } -
單表簡單查詢
HelloController.java
@RestController public class HelloController { @Autowired private PersonRespository personRespository; @PostMapping(value = "/addPerson") public Person addPerson(@RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age) { Person person = new Person(); person.setName(name); person.setAge(age); return personRespository.save(person); } @DeleteMapping(value = "/delPerson/{id}") public void delPerson(@PathVariable(value = "id") Integer id) { personRespository.delete(id); } @PutMapping(value = "/updatePerson") public Person updatePerson(@RequestParam(value = "id") Integer id, @RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age) { Person person = new Person(); person.setId(id); person.setName(name); person.setAge(age); return personRespository.save(person); } @GetMapping(value = "/findPerson/{id}") public Person findPerson(@PathVariable(value = "id") Integer id) { return personRespository.findOne(id); } @GetMapping(value = "/findPersons") public List<Person> findPerson() { return personRespository.findAll(); } } -
單表根據年齡查詢
PersonRespository.java
增加一個根據年齡查詢的抽象方法
public interface PersonRespository extends JpaRepository<Person, Integer> { Person findByAge(Integer age); }HelloController.java
@RestController public class HelloController { @Autowired private PersonRespository personRespository; @GetMapping(value = "/findPersonByAge/{age}") public Person findPersonByAge(@PathVariable(value = "age") Integer age) { return personRespository.findByAge(age); } }
事務管理
在方法名稱上增加@Transactional,該方法就有事務管理了。
@Service
public class PersonService {
@Autowired
private PersonRespository personRespository;
@Transactional
public void insertTwo() {
Person person = new Person();
person.setName("jack");
person.setAge(40);
personRespository.save(person);
Person person1 = new Person();
person1.setName("rose");
person1.setAge(30000);
int a = 1 / 0;
personRespository.save(person1);
}
}
校驗
在 model 增加注解 @Min(value = 18,message = "不能小于18歲")
@Entity
public class Person {
@Id
@GeneratedValue
private Integer id;
private String name;
@Min(value = 18,message = "不能小于18歲")
private Integer age;
。。。set、get 方法
}
在 controller 的 model 增加@Valid注解,同時可以BindingResult獲取校驗的信息。
@PostMapping(value = "/addPerson")
public Person addPerson(@Valid Person person, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
//輸出錯誤信息:不能小于18歲
System.out.print(bindingResult.getFieldError().getDefaultMessage());
}
return personRespository.save(person);
}
AOP
-
創(chuàng)建切面方式一:
@Aspect @Component public class HttpAspect { @Before("execution(public * com.example.HelloController.*(..))") public void logBefore() { System.out.print("logBefore"); } @After("execution(public * com.example.HelloController.*(..))") public void logAfter() { System.out.print("logAfter"); } } -
創(chuàng)建切面方式二:(抽取切點出來,減少重復代碼)
@Aspect @Component public class HttpAspect { @Pointcut("execution(public * com.example.HelloController.*(..))") public void log() { } @Before("log()") public void logBefore() { System.out.print("logBefore"); } @After("log()") public void logAfter() { System.out.print("logAfter"); } }
@Aspect
@Component
public class HttpAspect {
public static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.example.HelloController.*(..))")
public void log() {
}
@Before("log()")
public void logBefore(JoinPoint joinPoint) {
logger.info("logBefore");
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
logger.info("url={}", request.getRequestURL());
logger.info("method={}", request.getMethod());
logger.info("ip={}", request.getRemoteAddr());
logger.info("class.method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("args={}", joinPoint.getArgs());
}
@After("log()")
public void logAfter() {
logger.info("logAfter");
}
@AfterReturning(returning = "object", pointcut = "log()")
public void logAfterReturning(Object object) {
logger.info("response={}", object.toString());
}
}
輸出日志:
logBefore
url=http://localhost:8080/updatePerson
method=PUT
ip=0:0:0:0:0:0:0:1
class.method=com.example.HelloController.updatePerson
args=10
m person person0_ where person0_.id=?
logAfter
response=com.example.Person@34b98c82
日志
public static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.example.HelloController.*(..))")
public void log() {
}
@Before("log()")
public void logBefore() {
logger.info("logBefore");
}
@After("log()")
public void logAfter() {
logger.info("logAfter");
}
異常處理
定義常量枚舉:ResultEnum.java
public enum ResultEnum {
UNKNOW(-1, "未知錯誤"),
OKKK(100, "小于18歲"),
NOOO(101, "大于50歲"),;
private Integer code;
private String msg;
ResultEnum(Integer code, String mag) {
this.code = code;
this.msg = mag;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMag() {
return msg;
}
public void setMag(String mag) {
this.msg = mag;
}
}
自定義異常類:PersonException.java
public class PersonException extends Exception {
private Integer code;
private String msg;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public PersonException(ResultEnum resultEnum) {
this.code = resultEnum.getCode();
this.msg = resultEnum.getMag();
}
}
定義返回結果類:ResultInfo.java
public class ResultInfo<T> implements Serializable {
private int code;
private String msg;
private T data;
public ResultInfo(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
全局異常處理類:ResultExceptionHandle.java
@ControllerAdvice
public class ResultExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResultInfo handleException(Exception e) {
if (e instanceof PersonException) {
PersonException personException = (PersonException) e;
return new ResultInfo(personException.getCode(), personException.getMsg());
}
return new ResultInfo(-1, "未知錯誤");
}
}
Controller 正常調用,全局 Exception 會自動攔截處理 HelloController.java
@RestController
public class HelloController {
@Autowired
private PersonRespository personRespository;
@PostMapping(value = "/addPerson")
public Person addPerson(@Valid Person person, BindingResult bindingResult) throws Exception {
if (bindingResult.hasErrors()) {
//輸出錯誤信息
System.out.print(bindingResult.getFieldError().getDefaultMessage());
}
return personService.save(person);
}
}
單元測試
需要模擬 http 請求進行單元測試,類上要添加注解(@RunWith(SpringRunner.class)、@SpringBootTest、@AutoConfigureMockMvc),方法上也要添加注解(@Test),使用MockMvc進行請求模擬。
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class PersonControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void findPerson() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/findPersons")).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("hello"));
}
}
打包默認會運行所有單元測試,可以通過參數跳過單元測試。