用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 实现RESTful CRUD
来源:互联网 发布:淘宝办理出版物许可证 编辑:程序博客网 时间:2024/06/07 05:35
序
打算就”用Spring Boot & Cloud和Angular2快速搭建微服务web应用“这个题目写一系列文章,作为自己学习的一个记录。在参加完读脉组织的一个Java培训活动后,发现自己在这方面的知识已经落后好多年了。讲师Josh的激情演讲,也让我看到了自己和顶级程序员的差距。在此感谢读脉组织的这次活动,感谢Josh的激情演讲,给了我写这个系列文章的动力。
读脉:http://readmore.cc/
Josh:https://github.com/joshlong
一切从“Spring Initializr”开始
为了快速地搭建和运行Spring Boot项目,Pivotal提供了称之为“Spring Initializr”的web界面,用于下载预先定义好的Maven或Gradle构建配置。为实现RESTful CRUD,访问http://start.spring.io/,创建一个新的项目叫做user-service,为health-travel提供用户管理服务,并且选择如下依赖:Rest Repositories,JPA,MySQL。然后点击“Generate Project”会产生一个名为user-service的zip包,里面包含了项目需要的Maven工程文件。
打开pom.xml,可以看到项目的依赖已经生成好了:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.healtrav</groupId><artifactId>user-service</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>user-service</name><description>user management service for healtrav</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.4.0.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-rest</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
同时注意到以下几个依赖:
- spring-boot-starter-data-jpa:使用Spring Data JPA 读写数据。Spring Data JPA是Spring Data项目的一部分,用于简化持久层的业务逻辑。它会根据方法的名字来确定方法要实现什么样的业务逻辑,所以developer只要按照规范的名字去命名方法,声明接口。参考链接:http://projects.spring.io/spring-data-jpa/
- spring-boot-starter-data-rest:用RESTful的方式访问Spring Data数据仓库,提供了CRUD。参考链接:http://projects.spring.io/spring-data-rest/
Spring Initializr还生成了user-service的主程序文件UserServiceApplication.java
package com.healtrav;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}}现在我们只需要添加一些业务代码,就可以直接实现一个Restful,支持CRUD的web应用。
实现
添加domain/User.java
package com.healtrav.domain;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.validation.constraints.NotNull;@Entitypublic class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @NotNull private String username; @NotNull private String password; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }}
User对应数据库的user表。
添加repository/UserRepository.java
package com.healtrav.repository;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.repository.query.Param;import org.springframework.data.rest.core.annotation.RepositoryRestResource;import com.healtrav.domain.User;@RepositoryRestResource(collectionResourceRel = "user", path = "user")public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(@Param("username") String username);}
JpaRepository的详细信息:JpaRepository。前面提到过Spring Data JPA的命名规范,findByUsername就是利用了这样的规范,让Spring Data JPA实现按照username查找User。可以通过在方法名中添加Distinct,Asc,Desc,LessThen等来实现去除重复值,升序,降序,小于等的条件的查找,例如findDistinctByUsername。另外JpaRepository提供了大量的方法,从上面的链接可以看到,该接口及其继承的接口,提供了基本的查询,分页,删除,保存,修改,及批量功能。参考:http://docs.spring.io/spring-data/jpa/docs/current/reference/html/
修改resources/application.properties
# MySQL data source settingsspring.datasource.url=jdbc:mysql://localhost:3306/healtravspring.datasource.username=rootspring.datasource.password=spring.datasource.initial-size=20spring.datasource.max-idle=60spring.datasource.max-wait=10000spring.datasource.min-idle=10spring.datasource.max-active=200# auto create tables and data for database healtravspring.jpa.generate-ddl=truespring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialectspring.datasource.schema=..\..\..\db\schema.sqlspring.datasource.data=..\..\..\db\data.sql# show each sql for debugspring.jpa.show-sql = true
文件里面的datasource用来配置MySQL数据库连接。Spring Data还支持MongoDB,H2嵌入式数据库等。如果用MongoDB,H2等,只需要在Spring Initializr里面添加依赖,不需要添加datasource配置。另外配置增加了自动运行schema.sql和data.sql的功能,自动创建数据库表和添加数据(healtrav数据库必须已经存在)。show-sql是为了让Spring Data显示每个SQL语句,方便调试。
添加schema.sql
-- MySQL Script generated by MySQL Workbench-- 09/20/16 18:12:37-- Model: New Model Version: 1.0-- MySQL Workbench Forward EngineeringSET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';-- ------------------------------------------------------- Schema healtrav-- -----------------------------------------------------DROP SCHEMA IF EXISTS `healtrav` ;-- ------------------------------------------------------- Schema healtrav-- -----------------------------------------------------CREATE SCHEMA IF NOT EXISTS `healtrav` DEFAULT CHARACTER SET utf8 ;USE `healtrav` ;-- ------------------------------------------------------- Table `healtrav`.`user`-- -----------------------------------------------------DROP TABLE IF EXISTS `healtrav`.`user` ;CREATE TABLE IF NOT EXISTS `healtrav`.`user` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `username` VARCHAR(64) NOT NULL, `password` VARCHAR(128) NOT NULL, PRIMARY KEY (`id`), UNIQUE INDEX `id_UNIQUE` (`id` ASC), UNIQUE INDEX `username_UNIQUE` (`username` ASC))ENGINE = InnoDB;SET SQL_MODE=@OLD_SQL_MODE;SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
小结
短短的这些代码,已经实现了对库表user的CRUD功能,并且提供了标准的Restful API。文件UserRepository.java中的@RepositoryRestResource(collectionResourceRel = "user", path = "user")注解,在localhost:8080/user下面,生成了Restful API,甚至还有API的接口说明。
参考:https://spring.io/guides/gs/accessing-data-rest/
验证
Windows版本的git bash提供了很多有用的工具,其中一个就是curl。curl可以用来验证刚才建立的service。
在git bash中进入user-service目录,用mvn运行:./mvnw spring-boot:run
在另一个git bash中,运行命令:
$ curl http://localhost:8080/会得到当前的Restful URI列表。其中一个是"href" : "http://localhost:8080/user{?page,size,sort}",
运行命令:
$ curl http://localhost:8080/user会得到user路径下面的URI列表,及一个user数组。但是现在这个user数组是空的,因为我们还没有添加用户信息。
运行命令:
$ curl -i -X POST -H "Content-Type:application/json" -d '{ "username" : "cuiwader", "password" : "123" }' http://localhost:8080/user会添加数据到数据库,并且会返回新添加的用户的信息。
运行命令:
$ curl http://localhost:8080/user/search/findByUsername?username=cuiwader会调用UserRepository.java中,接口UserRepository的findByUsername方法。而且该方法的实现也是Spring Data JPA根据方法的名字自动生成的。
再次运行命令:
$ curl http://localhost:8080/user会得到user路径下面的URI列表,及一个user数组。这次这个数组多了一个元素,即刚才添加的那个元素,但是请大家仔细看下面的输出,数组元素没有id字段,因为默认id是不导出的。可以通过继承RepositoryRestMvcConfiguration,重写configureRepositoryRestConfiguration(RepositoryRestConfiguration config)方法,并且在方法里面调用
config.exposeIdsFor(class)的方式增加id导出。但是应该使用_links的href去调用后台,而不是自己拼接id。输出如下:
$ curl http://localhost:8080/user-service/user % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 726 0 726 0 0 15782 0 --:--:-- --:--:-- --:--:-- 15782{ "_embedded" : { "user" : [ { "username" : "cuiwader", "password" : "123", "_links" : { "self" : { "href" : "http://localhost:8080/user-service/user/1" }, "user" : { "href" : "http://localhost:8080/user-service/user/1" } } } ] }, "_links" : { "self" : { "href" : "http://localhost:8080/user-service/user" }, "profile" : { "href" : "http://localhost:8080/user-service/profile/user" }, "search" : { "href" : "http://localhost:8080/user-service/user/search" } }, "page" : { "size" : 20, "totalElements" : 1, "totalPages" : 1, "number" : 0 }}
解决复杂问题
这里还有一个遗留问题,如果业务逻辑特别复杂,不能通过简单的方法命名规范来实现怎么办呢?一般遇到这样的问题,只需要抱有一个信念:Spring如此灵活,不可能有解决不了的问题。另外自己遇到的问题,别人也一定遇到过,只是暂时还没有找到解决方案。目前我所知道的解决方案有3个:@Query,存储过程和定制实现。
@Query
推荐使用命名参数方式的@Query注解,还是以findByUsername为例:
@Query("select u from user u where u.username = :username") User findByUsername(@Param("username") String username);
存储过程
在User.java增加:
@Entity@NamedStoredProcedureQuery(name = "User.findByUsername", procedureName = "findByUsername", parameters = { @StoredProcedureParameter(mode = ParameterMode.IN, name = "username", type = String.class), @StoredProcedureParameter(mode = ParameterMode.OUT, name = "user", type = User.class) })public class User {...
在UserRepository中:
@Procedure("findByUsername") User findByUserName(String username);
当然数据库里面需要有一个findByUserName的存储过程。
定制实现
增加一个接口:
package com.healtrav.repository;import com.healtrav.domain.User;public interface UserRepositoryCustom { public User getByUsername(String username);}
修改UserRepository的定义:
package com.healtrav.repository;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.repository.query.Param;import org.springframework.data.rest.core.annotation.RepositoryRestResource;import com.healtrav.domain.User;@RepositoryRestResource(collectionResourceRel = "user", path = "user")public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom { User findByUsername(@Param("username") String username);}
添加UserRepositoryCustom的实现:
package com.healtrav.repository;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.rest.webmvc.RepositorySearchesResource;import org.springframework.hateoas.Link;import org.springframework.hateoas.ResourceProcessor;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import com.healtrav.domain.User;@RestController@RequestMapping("/user")public class UserRepositoryImpl implements UserRepositoryCustom, ResourceProcessor<RepositorySearchesResource> { @Autowired UserRepository userRepo; @Override @RequestMapping(value = "/search/getUserByUsername", method = RequestMethod.GET) public User getByUsername( @RequestParam(value = "username", required = true) String username) { return userRepo.findByUsername(username); } @Override public RepositorySearchesResource process( RepositorySearchesResource resource) { String href = resource.getId().getHref(); resource.add(new Link(href + "/getByUsername{?username}") .withRel("getByUsername")); return resource; }}
其实UserRepository继承UserRepositoryCustom没有什么实际的意义,Spring不会自动暴露UserRepositoryImpl到RESTful,意义在于让UserRepository提供了统一的访问接口。UserRepositoryImpl实现了ResourceProcessor反而更加重要,实际上在curl http://localhost:8081/user/search的时候,增加了一个输出:
"getByUsername" : { "href" : "http://localhost:8081/user/search/getByUsernamee{?username}", "templated" : true }
下一章:用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - AngularJS2客户端
0 0
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 实现RESTful CRUD
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 增加代理服务器
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - AngularJS2客户端
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 增加权限控制
- 基于Spring Boot和Spring Cloud实现微服务架构学习(三)-Spring Boot应用
- 基于Spring Boot和Spring Cloud实现微服务架构学习(三)-Spring Boot应用
- 基于Spring Boot和Spring Cloud实现微服务架构学习(三)-Spring Boot应用
- 基于Spring Boot和Spring Cloud实现微服务架构学习(三)-Spring Boot应用
- Spring-boot:快速搭建微服务框架
- 基于Spring Boot和Spring Cloud实现微服务架构学习(六)-Docker应用
- 基于Spring Boot和Spring Cloud实现微服务架构学习(六)-Docker应用
- 基于Spring Boot和Spring Cloud实现微服务架构学习(六)-Docker应用
- 基于Spring Boot和Spring Cloud实现微服务架构学习(六)-Docker应用
- 基于Spring Boot和Spring Cloud实现微服务架构学习(六)-Docker应用
- 快速搭建RESTful Web Service(Spring Boot)
- Spring Cloud微服务 Spring Boot Admin
- spring boot spring cloud微服务架构
- Spring Boot和Spring Cloud微服务架构学习(三)-Spring Boot应用
- 1.js的变量
- Android处理ANR步骤
- 0920-0929 tableView返回顶部/上架流程/一些小功能
- 彩信发送和接收关键流程
- Android报表库aChartEngine系列(介绍)
- 用Spring Boot & Cloud,Angular2快速搭建微服务web应用 - 实现RESTful CRUD
- Caused by: org.xml.sax.SAXParseException; lineNumber: 3; columnNumber: 44; 值为 "none" 的属性 "parallel"
- listview控件使用实例(二)
- WordPress绑定多个域名和禁止搜索引擎收录非主域名的方法
- 在Qt中利用window下的DirectShow获取摄像头名称示例
- Jersey构建RESTful服务1--HelloWorld
- ubuntu opencv compilation error/bug with cuda 8.0 RC
- Playmaker人物高级控制教程
- .so导入Bug