2019-2-24

一、《Spring Security开发安全的REST服务》视频笔记

1、Spring boot单元测试

eg:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {

	@Autowired
	private WebApplicationContext wac;

	private MockMvc mockMvc;

	@Before
	public void setup() {
		mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
	}
	
	@Test
	public void whenUploadSuccess() throws Exception {
		String result = mockMvc.perform(fileUpload("/file")
				.file(new MockMultipartFile("file", "test.txt", "multipart/form-data", "hello upload".getBytes("UTF-8"))))
				.andExpect(status().isOk())
				.andReturn().getResponse().getContentAsString();
		System.out.println(result);
	}
	

	@Test
	public void whenQuerySuccess() throws Exception {
		String result = mockMvc.perform(
				get("/user").param("username", "jojo").param("age", "18").param("ageTo", "60").param("xxx", "yyy")
						// .param("size", "15")
						// .param("page", "3")
						// .param("sort", "age,desc")
						.contentType(MediaType.APPLICATION_JSON_UTF8))
				.andExpect(status().isOk()).andExpect(jsonPath("$.length()").value(3))
				.andReturn().getResponse().getContentAsString();
		
		System.out.println(result);
	}

	@Test
	public void whenGetInfoSuccess() throws Exception {
		String result = mockMvc.perform(get("/user/1")
				.contentType(MediaType.APPLICATION_JSON_UTF8))
				.andExpect(status().isOk())
				.andExpect(jsonPath("$.username").value("tom"))
				.andReturn().getResponse().getContentAsString();
		
		System.out.println(result);
	}
	
	@Test
	public void whenGetInfoFail() throws Exception {
		mockMvc.perform(get("/user/a")
				.contentType(MediaType.APPLICATION_JSON_UTF8))
				.andExpect(status().is4xxClientError());
	}
	
	@Test
	public void whenCreateSuccess() throws Exception {
		
		Date date = new Date();
		System.out.println(date.getTime());
		String content = "{\"username\":\"tom\",\"password\":null,\"birthday\":"+date.getTime()+"}";
		String reuslt = mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
				.content(content))
				.andExpect(status().isOk())
				.andExpect(jsonPath("$.id").value("1"))
				.andReturn().getResponse().getContentAsString();
		
		System.out.println(reuslt);
	}
	
	@Test
	public void whenCreateFail() throws Exception {
		
		Date date = new Date();
		System.out.println(date.getTime());
		String content = "{\"username\":\"tom\",\"password\":null,\"birthday\":"+date.getTime()+"}";
		String reuslt = mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
				.content(content))
//				.andExpect(status().isOk())
//				.andExpect(jsonPath("$.id").value("1"))
				.andReturn().getResponse().getContentAsString();
		
		System.out.println(reuslt);
	}
	
	@Test
	public void whenUpdateSuccess() throws Exception {
		
		Date date = new Date(LocalDateTime.now().plusYears(1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
		System.out.println(date.getTime());
		String content = "{\"id\":\"1\", \"username\":\"tom\",\"password\":null,\"birthday\":"+date.getTime()+"}";
		String reuslt = mockMvc.perform(put("/user/1").contentType(MediaType.APPLICATION_JSON_UTF8)
				.content(content))
				.andExpect(status().isOk())
				.andExpect(jsonPath("$.id").value("1"))
				.andReturn().getResponse().getContentAsString();
		
		System.out.println(reuslt);
	}
	
	@Test
	public void whenDeleteSuccess() throws Exception {
		mockMvc.perform(delete("/user/1")
				.contentType(MediaType.APPLICATION_JSON_UTF8))
				.andExpect(status().isOk());
	}

}

  

2、请求url正则表达式

eg:

@PutMapping("/{id:\\d+}")

3、@JsonView注解

使用步骤:

(1)使用接口来声明多个视图

public class User {
	
	public interface UserSimpleView {};
	public interface UserDetailView extends UserSimpleView {};
	
	private String id;
	
	@MyConstraint(message = "这是一个测试")
	@ApiModelProperty(value = "用户名")
	private String username;
	
	@NotBlank(message = "密码不能为空")
	private String password;
	
	@Past(message = "生日必须是过去的时间")
	private Date birthday;

	@JsonView(UserSimpleView.class)
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@JsonView(UserDetailView.class)
	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@JsonView(UserSimpleView.class)
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
	
	@JsonView(UserSimpleView.class)
	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	
}

  

上面声明了UserSimpleView和UserDetailView两个接口。

(2)在值对象的get方法上指定视图

例如上述代码中,有两处不同:

@JsonView(UserSimpleView.class)
	public String getUsername() {
		return username;
	}

  和

@JsonView(UserDetailView.class)
	public String getPassword() {
		return password;
	}

  而且由于UserSimpleView和UserDetailView是继承关系,所以显示密码的地方也会显示用户名。

(3)在Controller方法上指定视图

例如:

@GetMapping
	@JsonView(User.UserSimpleView.class)
	@ApiOperation(value = "用户查询服务")
	public List<User> query(UserQueryCondition condition,
			@PageableDefault(page = 2, size = 17, sort = "username,asc") Pageable pageable) {

		System.out.println(ReflectionToStringBuilder.toString(condition, ToStringStyle.MULTI_LINE_STYLE));

		System.out.println(pageable.getPageSize());
		System.out.println(pageable.getPageNumber());
		System.out.println(pageable.getSort());

		List<User> users = new ArrayList<>();
		users.add(new User());
		users.add(new User());
		users.add(new User());
		return users;
	}

  和

        @GetMapping("/{id:\\d+}")
	@JsonView(User.UserDetailView.class)
	public User getInfo(@ApiParam("用户id") @PathVariable String id) {
//		throw new RuntimeException("user not exist");
		System.out.println("进入getInfo服务");
		User user = new User();
		user.setUsername("tom");
		return user;
	}

  

4、@RequestBody映射请求体到java方法的参数

eg:

后台接收:

public User create(@RequestBody User user)

前端发送json字符串:

@Test
public void whenCreateSuccess() throws Exception {

Date date = new Date();
System.out.println(date.getTime());
String content = "{\"username\":\"tom\",\"password\":null,\"birthday\":"+date.getTime()+"}";
String reuslt = mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
.content(content))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value("1"))
.andReturn().getResponse().getContentAsString();

System.out.println(reuslt);
}

5、日期类型参数的处理

后台统一返回时间戳,前端根据自己的需求将时间戳转成特定格式的日期时间。

eg:

Date date = new Date();
String content = "{\"username\":\"tom\",\"password\":null,\"birthday\":"+date.getTime()+"}";

6、@Valid注解和BindingResult验证请求参数的合法性并处理校验结果

愚蠢的逐个校验(代码重构时不方便维护):

if(StringUtils.isNotBlank(pwd)){

}

  可以使用@NotBlank:

public class User {
	
	public interface UserSimpleView {};
	public interface UserDetailView extends UserSimpleView {};
	
	private String id;
	
	@MyConstraint(message = "这是一个测试")
	@ApiModelProperty(value = "用户名")
	private String username;
	
	@NotBlank(message = "密码不能为空")
	private String password;
}

  

但如果仅仅只加这个注解是不行的!!!还要在控制器方法中配合@Valid注解使用:

        @PostMapping
	@ApiOperation(value = "创建用户")
	public User create(@Valid @RequestBody User user) {

		System.out.println(user.getId());
		System.out.println(user.getUsername());
		System.out.println(user.getPassword());
		System.out.println(user.getBirthday());

		user.setId("1");
		return user;
	}

  注意:如果没有加上BindingResult参数,且传进来的password为空,则该方法根本不会执行,而是直接报错!!!如果想要知道是发生了什么错误并且能进入方法进行处理,则:

        @PostMapping
	@ApiOperation(value = "创建用户")
	public User create(@Valid @RequestBody User user, BindingResult errors) {
    
                if(errors.hasErrors()){
                    errors.getAllErrors().stream().forEach(err->System.out.println(err.getDefaultMessage()));
                }

		System.out.println(user.getId());
		System.out.println(user.getUsername());
		System.out.println(user.getPassword());
		System.out.println(user.getBirthday());

		user.setId("1");
		return user;
	}    

  

扩展:还有很多常用的验证注解在Hibernate Validator可以查看。

7、自定义校验注解

(1)创建注解(

注意:

@Constraint(validatedBy = MyConstraintValidator.class)

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator.class)
public @interface MyConstraint {
	
	String message();

	Class<?>[] groups() default { };

	Class<? extends Payload>[] payload() default { };

}

  

(2)定义刚刚这个注解的校验逻辑由谁来执行(泛型参数中,第一个是注解名,第二个是注解适合用在什么类型的参数)

public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Object> {

	@Autowired
	private HelloService helloService;
	
	@Override
	public void initialize(MyConstraint constraintAnnotation) {
		System.out.println("my validator init");
	}

	@Override
	public boolean isValid(Object value, ConstraintValidatorContext context) {
		helloService.greeting("tom");
		System.out.println(value);
		return true;
	}

}

(3)使用注解:

        @MyConstraint(message = "这是一个测试")
	private String username;

  

8、Spring Boot中默认的错误处理机制和自定义异常处理

可以使用chrome的一个插件来模拟app的请求:Restlet Client

SpringBoot默认的错误处理机制是:检测到是浏览器发出,则返回html;是app发出,则返回json字符串。源码在BasicErrorController

二、java8新增时间api:LocalDateTime类

猜你喜欢

转载自www.cnblogs.com/z-y-x/p/10426974.html
今日推荐