restful简介

1 简介

基本理念


查询 /user/query?name=tom   		GET     /user?name=tom    	GET
详情 /user/getInfo?id=1			GET 	/user/1				GET
创建 /user/create?name=tom		POST 	/user				POST
修改 /user/update?id=1&name=tom	POST 	/user/1				PUT
修改 /user/delete?id=1			GET 	/user/1				DELETE

1.用URL描述资源
2.使用HTTP方法描述行为。使用HTTP状态码来表示不同的结果。
3.使用json交互数据
4.RESTful只是一种风格,并不是强制的标准。

基本代码

  1. 使用@REstController 标注此Controller 提供RestAPI
@RestController  
public class  UserController {
}
  1. @RequestParam 映射请求方法
//@RequestParam 映射请求方法
 @GetMapping("/user")  
  public List<User> query(@RequestParam(name = "username")  String userName){}
  1. Pageable
// 分页参数
//查询结构体
public class UserQueryCondition {
    private String username;
    private int age;
    private int ageto;
    private String xxx;}
	@GetMapping("/user")
	
    public List<User> query(UserQueryCondition condition, 
                            @PageableDefault(page = 1,size = 17,sort = "username,asc") Pageable  pageable){}
  1. @PathVariable 映射url片断到java 方法的参数,在url中可使用正则
    @GetMapping("/user/{id:\\d+}")
    public User getInfo(@PathVariable String id){ }         
  1. @jsonView控制json 输出内容

    @JsonView 使用步骤
    使用接口声明多个视图
    在值对象的get 方法上指定视图
    在Controller 方法上指定视图

在这里插入代码片
public class User {
//    声明接口
    public interface UserSimpleView { };
    public interface UserDetailView extends UserSimpleView { };
    private String username;
    private String password;
//    get接口上指定视图
    @JsonView(UserSimpleView.class)
    public String getUsername() {
        return username;
    }
    @JsonView(UserDetailView.class)
    public String getPassword() {
        return password;
    }}

 在Controller 方法上指定视图
 //    分页参数
    @GetMapping("/user")
//    @JsonView(User.UserSimpleView.class)
    public List<User> query(UserQueryCondition condition,
                            @PageableDefault(page = 1,size = 17,sort = "username,asc") Pageable  pageable){
        System.out.println( pageable.getPageNumber());
        System.out.println( pageable.getPageSize());
        System.out.println( pageable.getSort());
        System.out.println(ReflectionToStringBuilder.toString(condition, ToStringStyle.MULTI_LINE_STYLE));

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


    @JsonView(User.UserDetailView.class)
    @GetMapping("/user/{id:\\d+}")
    public User getInfo(@PathVariable String id){
        User user =new User();
        user.setUsername("tom");
        return  null;
    }

8.简单校验

//实体
  public class User {
    private String id;
    private String username;
   @NotBlank(message = "密码不能为空")
    private String password;
    private Date birthday;
    }
    
        /**
     *  只有 @Valid 传入字段校验不过,拦截器会直接返回
     *  加入BindingResult后,会进入函数,然后写代码自己判断
     * */
    @PostMapping
    public User create(@Valid @RequestBody User user, BindingResult error) {
//        如果有错返回true 没错返回false
        if(error.hasErrors()){
            error.getAllErrors().stream().forEach(e->{
                  FieldError fieldError=(FieldError)e;
                System.out.println(fieldError.getField());
                System.out.println(e.getDefaultMessage());
            });
        }

//其它注解
    @NotNull //值不能为空
    private String username1;
    @Null //必须为空
    private String username2;
    @Pattern(regexp = "") //字符串必需匹配正则表达式
    private String username3;
    @Size(min=1,max = 5) //集合的元素数量必需在min和max之间
    private String username4;
    @Email //字符串必需是email
    private String username5;
    @Length(min=1,max = 8) // 检查字符串长度
    private String username6;
    @NotBlank //字符串必需有字符
    private String username7;
    @NotEmpty //字符串不为null,集合有元素
    private String username8;
    @Range(min = 0,max=9) //数字必需大于等于min 小于等于max
    private String username10;
    @URL //字符串是合法的url
    private String username9;

9.复杂校验

第一步 定义注解
第二步 定义校验所用的校验类

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator.class) //校验专用,指定用哪个类校验
public @interface MyConsraint {
    String message();
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}

/**
 *  参数有两个,一个是注解,另一个是校验的类型,写成Object就可以加到任何类型字段上面
 */
public class MyConstraintValidator implements ConstraintValidator<MyConsraint, Object> {
   /**
	* 这只主要是为了说明 不用在类上加任何标记。就可以直接使用 spring 注入
	* */
	@Autowired
	private HelloService helloService;
   
   // 初始化
	@Override
	public void initialize(MyConsraint constraintAnnotation) {
		System.out.println("my validator init");
	}

	// 初始化校验逻辑
	@Override
	public boolean isValid(Object value, ConstraintValidatorContext context) {
		System.out.println(value);
		return true;
	}
}
  1. 错误处理
    浏览器自定义出错页面
    在这里插入图片描述
    json 自定义格式
第一步 定义错误类型
第二步 定义错误用的controller
public class UserNotExistException extends RuntimeException {
	private static final long serialVersionUID = -6112780192479692859L;
	private String id;
	public UserNotExistException(String id) {

		super("user not exist");
		this.id = id;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}

}


@ControllerAdvice  //这个注解的意思就是说 不接收任何请求,只处理错误信息
public class ControllerExceptionHandler {

	@ExceptionHandler(UserNotExistException.class) //这个注解意思是指定错误类型
	@ResponseBody
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public Map<String, Object> handleUserNotExistException(UserNotExistException ex) {
		Map<String, Object> result = new HashMap<>();
		result.put("id", ex.getId());
		result.put("message", ex.getMessage());
		return result;
	}
}

  1. 过滤器
第一步 定义过滤器
第二步 定义配置

/**
 * 过滤器,这玩意是javaEE的,可以拿到原始的http请求和响应的信息,但是拿不到具体的方法
 */
public class TimeFilter implements Filter {

	/* (non-Javadoc)
	 * @see javax.servlet.Filter#destroy()
	 */
	@Override
	public void destroy() {
		System.out.println("time filter destroy");
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("time filter start");
		long start = new Date().getTime();
		chain.doFilter(request, response);
		System.out.println("time filter 耗时:"+ (new Date().getTime() - start));
		System.out.println("time filter finish");
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		System.out.println("time filter init");
	}

}

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
	@Bean
	public FilterRegistrationBean timeFilter() {
		FilterRegistrationBean registrationBean = new FilterRegistrationBean();
		TimeFilter timeFilter = new TimeFilter();
		registrationBean.setFilter(timeFilter);
		List<String> urls = new ArrayList<>();
		urls.add("/*");
		registrationBean.setUrlPatterns(urls);
		return registrationBean;
	}
}

  1. 拦截器
第一步 定义过滤器
第二步 定义配置
/**
 * 既可以拿到原始的http请求和响应的信息,也可以拿到方法信息,但是拿不到具体参数值。
 */
public class TimeInterceptor implements HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("preHandle");
		System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
		System.out.println(((HandlerMethod)handler).getMethod().getName());
		request.setAttribute("startTime", new Date().getTime());
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle");
		Long start = (Long) request.getAttribute("startTime");
		System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("afterCompletion");
		Long start = (Long) request.getAttribute("startTime");
		System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));
		System.out.println("ex is "+ex);
	}

}

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
	
	@Autowired
	private TimeInterceptor timeInterceptor;
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(timeInterceptor);
	}
}

  1. 切面
/**
 * 可以拿到具体参数值,但是拿不到原始的http请求和响应的信息
 */
@Aspect
@Component
public class TimeAspect {

	@Around("execution(* com.lgx.web.controller.UserController.*(..))")
	public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("time aspect start");
		Object[] args = pjp.getArgs();
		for (Object arg : args) {
			System.out.println("arg is "+arg);
		}
		long start = new Date().getTime();
		Object object = pjp.proceed();
		System.out.println("time aspect 耗时:"+ (new Date().getTime() - start));
		System.out.println("time aspect end");
		return object;
	}

}

在这里插入图片描述
12.文件上传下载

@RestController
@RequestMapping("/file")
public class FileController {

	private String folder = "/Users/zhailiang/Documents/my/muke/inaction/java/workspace/github/imooc-security-demo/src/main/java/com/imooc/web/controller";

	@PostMapping
	public FileInfo upload(MultipartFile file) throws Exception {

		System.out.println(file.getName());
		System.out.println(file.getOriginalFilename());
		System.out.println(file.getSize());

		File localFile = new File(folder, new Date().getTime() + ".txt");

//		file.getInputStream()
		
		file.transferTo(localFile);

		return new FileInfo(localFile.getAbsolutePath());
	}

	@GetMapping("/{id}")
	public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws Exception {

		try (InputStream inputStream = new FileInputStream(new File(folder, id + ".txt"));
				OutputStream outputStream = response.getOutputStream();) {
			
			response.setContentType("application/x-download");
			response.addHeader("Content-Disposition", "attachment;filename=test.txt");
			
			IOUtils.copy(inputStream, outputStream);
			outputStream.flush();
		} 

	}

}

2.多线程

2.1 Callable

@RestController
public class AsyncController {
    private Logger logger= LoggerFactory.getLogger(getClass());
    @RequestMapping("/order1")
    public Callable<String> order1() throws Exception{
        logger.info("主线程开始");
        Callable<String> result = new Callable<String>() {
            @Override
            public String call() throws Exception {
                logger.info("副线程开始");
                Thread.sleep(1000);
                logger.info("副线程返回");
                return "success";
            }
        };

        logger.info("主线程结束");
        return result;
    }
    }

2.2 DeferredResult
示意图
在这里插入图片描述

/**
 * 定义模拟消息队列
 */
@Component
public class MockQueue {

	private String placeOrder;

	private String completeOrder;
	
	private Logger logger = LoggerFactory.getLogger(getClass());

	public String getPlaceOrder() {
		return placeOrder;
	}

	public void setPlaceOrder(String placeOrder) throws Exception {
		new Thread(() -> {
			logger.info("接到下单请求, " + placeOrder);
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				e.printStackTrace();
			}
			this.completeOrder = placeOrder;
			logger.info("下单请求处理完毕," + placeOrder);
		}).start();
	}

	public String getCompleteOrder() {
		return completeOrder;
	}

	public void setCompleteOrder(String completeOrder) {
		this.completeOrder = completeOrder;
	}

}


/**
 *  消息队列监听器
 */
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {

	@Autowired
	private MockQueue mockQueue;

	@Autowired
	private DeferredResultHolder deferredResultHolder;
	
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		new Thread(() -> {
			while (true) {

				if (StringUtils.isNotBlank(mockQueue.getCompleteOrder())) {
					
					String orderNumber = mockQueue.getCompleteOrder();
					logger.info("返回订单处理结果:"+orderNumber);
					deferredResultHolder.getMap().get(orderNumber).setResult("place order success");
					mockQueue.setCompleteOrder(null);
					
				}else{
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

			}
		}).start();
	}
}

/**
 *  定义上下文
 */
@Component
public class DeferredResultHolder {
	
	private Map<String, DeferredResult<String>> map = new HashMap<String, DeferredResult<String>>();

	public Map<String, DeferredResult<String>> getMap() {
		return map;
	}

	public void setMap(Map<String, DeferredResult<String>> map) {
		this.map = map;
	}
	
}

/**
 * 控制器
 * */
@RestController
public class AsyncController {
    private Logger logger= LoggerFactory.getLogger(getClass());
    @Autowired
    private MockQueue mockQueue;
    @Autowired
    private DeferredResultHolder deferredResultHolder;

    @RequestMapping("/order2")
    public DeferredResult<String> order2() throws Exception {
        logger.info("主线程开始");
        String orderNumber = RandomStringUtils.randomNumeric(8);
        mockQueue.setPlaceOrder(orderNumber);
        DeferredResult<String> result = new DeferredResult<>();
        deferredResultHolder.getMap().put(orderNumber, result);
        return result;
    }}

3.打印实体

   <dependency>

   <groupId>commons-lang</groupId>
   <artifactId>commons-lang</artifactId>
   </dependency>

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

   com.lgx.dto.UserQueryCondition@b3857e2[
   username=jojo
   age=18
   ageto=60
   xxx=yyy
   ]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值