我们将创建一个简单的工资服务来管理公司的员工。我们将员工对象存储在(内存中的H2)数据库中,并访问它们(通过一种称为JPA的东西)。然后我们将用允许通过互联网访问的东西(称为Spring MVC层)来包装它。
1.定义职工
package payroll;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
//@Entity是JPA注释,用于使该对象准备好存储在基于JPA的数据存储中。
//id、name和role是我们员工域对象的属性。id用更多的JPA注释标记,以表明它是主键,并由JPA提供商自动填充。
class Employee {
private @Id @GeneratedValue Long id;
private String name;
private String role;
Employee() {}
Employee(String name, String role) {
this.name = name;
this.role = role;
}
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getRole() {
return this.role;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setRole(String role) {
this.role = role;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Employee))
return false;
Employee employee = (Employee) o;
return Objects.equals(this.id, employee.id) && Objects.equals(this.name, employee.name)
&& Objects.equals(this.role, employee.role);
}
@Override
public int hashCode() {
return Objects.hash(this.id, this.name, this.role);
}
@Override
public String toString() {
return "Employee{" + "id=" + this.id + ", name='" + this.name + '\'' + ", role='" + this.role + '\'' + '}';
}
}
2.获取数据
使用Spring Data JPA来处理繁琐的数据库交互。Spring Data JPA存储库是与支持针对后端数据存储创建、读取、更新和删除记录的方法的接口。一些存储库还支持适当的数据分页和排序。
Spring使访问数据变得容易。通过简单地声明以下EmployeeRepository
界面,我们将自动能够创建新员工;更新现有的;删除员工;查找员工。
package payroll;
import org.springframework.data.jpa.repository.JpaRepository;
interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
为了获得所有这些免费功能,我们所要做的就是声明一个扩展Spring Data JPA的JpaRepository
的接口,将域类型指定为Employee
,并将id类型指定为Long
。
此时就足以启动一个应用程序。
package payroll;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//@SpringBootApplication是一个元注释,可以拉动组件扫描、自动配置和属性支持。启动一个servlet容器并提供服务。
public class PayrollApplication {
public static void main(String... args) {
SpringApplication.run(PayrollApplication.class, args);
}
}
但是此时还没有数据,最好还是加上数据才直观。
package payroll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
class LoadDatabase {
private static final Logger log = LoggerFactory.getLogger(LoadDatabase.class);
@Bean
CommandLineRunner initDatabase(EmployeeRepository repository) {
return args -> {
log.info("Preloading " + repository.save(new Employee("Bilbo Baggins", "burglar")));
log.info("Preloading " + repository.save(new Employee("Frodo Baggins", "thief")));
};
}
}
右键单击并运行PayRollApplication
,将显示数据预加载的控制台输出片段
...2018-08-09 11:36:26.169 INFO 74611 --- [main] payroll.LoadDatabase:预加载员工(id=1,name=Bilbo Baggins,role=burglar)2018-08-09 11:36:26.174 INFO 74611 --- [main] payroll.LoadDatabase:预加载员工(id=2,姓名=Frodo Baggins,角色=小偷)...
首先运行CommandLineRunner
beans;然后该运行器将请求您刚刚创建EmployeeRepository
的副本。将创建两个实体并存储它们。
3.使用HTTP平台访问
package payroll;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
class EmployeeController {
private final EmployeeRepository repository;
EmployeeController(EmployeeRepository repository) {
this.repository = repository;
}
// Aggregate root
// tag::get-aggregate-root[]
@GetMapping("/employees")
List<Employee> all() {
return repository.findAll();
}
// end::get-aggregate-root[]
@PostMapping("/employees")
Employee newEmployee(@RequestBody Employee newEmployee) {
return repository.save(newEmployee);
}
// Single item
@GetMapping("/employees/{id}")
Employee one(@PathVariable Long id) {
return repository.findById(id)
.orElseThrow(() -> new EmployeeNotFoundException(id));
}
@PutMapping("/employees/{id}")
Employee replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {
return repository.findById(id)
.map(employee -> {
employee.setName(newEmployee.getName());
employee.setRole(newEmployee.getRole());
return repository.save(employee);
})
.orElseGet(() -> {
newEmployee.setId(id);
return repository.save(newEmployee);
});
}
@DeleteMapping("/employees/{id}")
void deleteEmployee(@PathVariable Long id) {
repository.deleteById(id);
}
}
-
@RestController
表示每种方法返回的数据将直接写入响应主体,而不是渲染模板。 -
构造函数将
EmployeeRepository
注入控制器。 -
我们有每个操作的路由(@
@GetMapping
,@PostMapping
,@PutMapping
和@DeleteMapping
,对应HTTPGET
,POST
,PUT
和DELETE
调用)。 -
EmployeeNotFoundException
是用于指示员工被查找但未找到时的例外。
package payroll;
class EmployeeNotFoundException extends RuntimeException {
EmployeeNotFoundException(Long id) {
super("Could not find employee " + id);
}
}
package payroll;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
class EmployeeNotFoundAdvice {
@ResponseBody
@ExceptionHandler(EmployeeNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
String employeeNotFoundHandler(EmployeeNotFoundException ex) {
return ex.getMessage();
}
}
-
@ResponseBody
表明此建议直接传达给响应机构。 -
@ExceptionHandler
将建议配置为仅在抛出EmployeeNotFoundException
时做出响应。 -
@ResponseStatus
说要发布HttpStatus.NOT_FOUND
,即HTTP 404。 -
建议的主体生成内容。在这种情况下,它会给出异常的信息。
4.最终结果
除了直接在网站的url上进行操作,还可以使用命令行
$ curl -v localhost:8080/employees/99$ curl -X POST localhost:8080/employees -H 'Content-type:application/json' -d '{"name": "Samwise Gamgee", "role": "gardener"}'$ curl -X PUT localhost:8080/employees/3 -H 'Content-type:application/json' -d '{"name": "Samwise Gamgee", "role": "ring bearer"}'$ curl -X DELETE localhost:8080/employees/3 #现在如果我们再看一遍,它就不见了 $ curl localhost:8080/employees/3 #找不到员工3