注解
学Spring boot有一阵子了,总结一下它的注解。
@Controller :修饰class,⽤来创建处理http请求的对象
@RestController :Spring4之后加⼊的注解,原来在 @Controller 中返回json需要 @ResponseBody 来配合,如果直接⽤ @RestController 替代 @Controller 就不需要再配置 @ResponseBody ,默认返回json格式。
@RequestMapping :配置url映射
例子:
实现对User对象的操作接⼝
@RestController
@RequestMapping(value="/users") // 通过这⾥配置使下⾯的映射都在/users下
public class UserController {
// 创建线程安全的Map
static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());
@RequestMapping(value="/", method=RequestMethod.GET)
public List<User> getUserList() {
// 处理"/users/"的GET请求,⽤来获取⽤户列表
// 还可以通过@RequestParam从⻚⾯中传递参数来进⾏查询条件或者翻⻚信息的传递
List<User> r = new ArrayList<User>(users.values());
return r;
}
@RequestMapping(value="/", method=RequestMethod.POST)
public String postUser(@ModelAttribute User user) {
// 处理"/users/"的POST请求,⽤来创建User
// 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从⻚⾯中传递参数
users.put(user.getId(), user);
return "success";
}
@RequestMapping(value="/{id}", method=RequestMethod.GET)
public User getUser(@PathVariable Long id) {
// 处理"/users/{id}"的GET请求,⽤来获取url中id值的User信息
// url中的id可通过@PathVariable绑定到函数的参数中
return users.get(id);
}
@RequestMapping(value="/{id}", method=RequestMethod.PUT)
public String putUser(@PathVariable Long id, @ModelAttribute User user) {
// 处理"/users/{id}"的PUT请求,⽤来更新User信息
User u = users.get(id);
u.setName(user.getName());
u.setAge(user.getAge());
users.put(id, u);
return "success";
}
@RequestMapping(value="/{id}", method=RequestMethod.DELETE)
public String deleteUser(@PathVariable Long id) {
// 处理"/users/{id}"的DELETE请求,⽤来删除User
进行验证,使用MockMvc
MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,使得测试速度快、不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。
接口MockMvcBuilder,提供一个唯一的build方法,用来构造MockMvc。主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。MockMvcBuilders提供了对应的创建方法standaloneSetup方法和webAppContextSetup方法,在使用时直接调用即可。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
public class ApplicationTests {
private MockMvc mvc;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
}
@Test
public void testUserController() throws Exception {
// 测试UserController
RequestBuilder request = null;
// 1、get查⼀下user列表,应该为空
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[]")));
// 2、post提交⼀个user
request = post("/users/")
.param("id", "1")
.param("name", "测试⼤师")
.param("age", "20");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));
// 3、get获取user列表,应该有刚才插⼊的数据
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[{\"id\":1,\"name\":\"测试⼤师\",\"age
\":20}]")));
// 4、put修改id为1的user
request = put("/users/1")
.param("name", "测试终极⼤师")
.param("age", "30");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));
// 5、get⼀个id为1的user
request = get("/users/1");
mvc.perform(request)
.andExpect(content().string(equalTo("{\"id\":1,\"name\":\"测试终极⼤师\",\"a
ge\":30}")));
// 6、del删除id为1的user
request = delete("/users/1");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));
// 7、get查⼀下user列表,应该为空
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[]")));
}
}
springboot-restful ⼯程项⽬结构介绍
springboot-restful ⼯程项⽬结构如下图所示:
org.spring.springboot.controller - Controller 层
org.spring.springboot.dao - 数据操作层 DAO
org.spring.springboot.domain - 实体类
org.spring.springboot.service - 业务逻辑层
Application - 应⽤启动类
application.properties - 应⽤配置⽂件,应⽤启动会⾃动读取配置
什么是 REST?
REST 是属于 WEB ⾃身的⼀种架构⻛格,是在 HTTP 1.1 规范下实现的。Representational State Transfer 全称翻译为表现层状态转化。Resource:资源。⽐如 newsfeed;Representational:表现形式,⽐如⽤JSON,富⽂本等;State Transfer:状态变化。通过HTTP 动作实现。
理解 REST ,要明⽩五个关键要素:
资源(Resource)
资源的表述(Representation)
状态转移(State Transfer)
统⼀接⼝(Uniform Interface)
超⽂本驱动(Hypertext Driven)
6 个主要特性:
⾯向资源(Resource Oriented)
可寻址(Addressability)
连通性(Connectedness)
⽆状态(Statelessness)
统⼀接⼝(Uniform Interface)
超⽂本驱动(Hypertext Driven)
CityRestController.java 城市 Controller 实现 Restful HTTP 服务:
public class CityRestController {
@Autowired
private CityService cityService;
@RequestMapping(value = "/api/city/{id}", method = RequestMethod.GET)
public City findOneCity(@PathVariable("id") Long id) {
return cityService.findCityById(id);
}
@RequestMapping(value = "/api/city", method = RequestMethod.GET)
public List<City> findAllCity() {
return cityService.findAllCity();
}
@RequestMapping(value = "/api/city", method = RequestMethod.POST)
public void createCity(@RequestBody City city) {
cityService.saveCity(city);
}
@RequestMapping(value = "/api/city", method = RequestMethod.PUT)
public void modifyCity(@RequestBody City city) {
cityService.updateCity(city);
}
@RequestMapping(value = "/api/city/{id}", method = RequestMethod.DELETE)
public void modifyCity(@PathVariable("id") Long id) {
cityService.deleteCity(id);
}
}
@RequestMapping 处理请求地址映射。
method - 指定请求的⽅法类型:POST/GET/DELETE/PUT 等
value - 指定实际的请求地址
consumes - 指定处理请求的提交内容类型,例如 Content-Type 头部设置application/json,text/html
produces - 指定返回的内容类型
Springboot 实现 Restful 服务,基于 HTTP / JSON 传输,适⽤于前后端分离
通过 @ApiOperation 注解来给API增加说明、通
过 @ApiImplicitParams 、 @ApiImplicitParam 注解来给参数增加说明。
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.didispace.web"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring Boot中使⽤Swagger2构建RESTful APIs")
.description("Spring Boot⽂章:http://blog.didispace.com/")
.termsOfServiceUrl("http://blog.didispace.com/")
.contact("程序猿D")
.version("1.0")
.build();
}
}
如上代码所示,通过 @Configuration 注解,让Spring来加载该类配置。再通过 @EnableSwagger2 注解
来启⽤Swagger2。
再通过 createRestApi 函数创建 Docket 的Bean之后, apiInfo() ⽤来创建该Api的基本信息(这些
基本信息会展现在⽂档⻚⾯中)。 select() 函数返回⼀个 ApiSelectorBuilder 实例⽤来控制哪些接
⼝暴露给Swagger来展现,本例采⽤指定扫描的包路径来定义,Swagger会扫描该包下所有Controller
定义的API,并产⽣⽂档内容(除了被 @ApiIgnore 指定的请求)。
@ApiOperation 注解来给API增加说明、通
过 @ApiImplicitParams 、 @ApiImplicitParam 注解来给参数增加说明。
springboot-freemarker ⼯程配置详解
pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSc
hema-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>springboot</groupId>
<artifactId>springboot-freemarker</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-freemarker :: Spring Boot 集成 FreeMarker 案例</name>
<!-- Spring Boot 启动⽗依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>
<properties>
<mybatis-spring-boot>1.2.0</mybatis-spring-boot>
<mysql-connector>5.1.39</mysql-connector>
</properties>
<dependencies>
<!-- Spring Boot Freemarker 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- Spring Boot Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Test 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot}</version>
</dependency>
<!-- MySQL 连接驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector}</version>
</dependency>
<!-- Junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
然后在 application.properties 中加⼊ FreeMarker 相关的配置:
Freemarker 配置
#⽂件配置路径
spring.freemarker.template-loader-path=classpath:/web/
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl
使用freemarker时非前后端分离,此时的Controller层:
3.展示层 Controller 详解
/**
* 城市 Controller 实现 Restful HTTP 服务
* <p>
* Created by bysocket on 07/02/2017.
*/
@Controller
public class CityController {
@Autowired
private CityService cityService;
@RequestMapping(value = "/api/city/{id}", method = RequestMethod.GET)
public String findOneCity(Model model, @PathVariable("id") Long id) {
model.addAttribute("city", cityService.findCityById(id));
return "city";
}
@RequestMapping(value = "/api/city", method = RequestMethod.GET)
public String findAllCity(Model model) {
List<City> cityList = cityService.findAllCity();
model.addAttribute("cityList",cityList);
return "cityList";
}
}
a.这⾥不是⾛ HTTP + JSON 模式,使⽤了 @Controller ⽽不是先前的 @RestController
b.⽅法返回值是 String 类型,和 application.properties 配置的 Freemarker ⽂件配置路径下的各个 *.ftl⽂件名⼀致。这样才会准确地把数据渲染到 ftl ⽂件⾥⾯进⾏展示。
c.⽤ Model 类,向 Model 加⼊数据,并指定在该数据在 Freemarker 取值指定的名称。