雪一更--软件开发--Spring boot web 交互

目的:Spring boot web 交互良好示例的学习


@CookieValue 注解的传入请求中的 cookie 值


 统一的controller 异常处理器

异常处理 bean 捕获异常, 实现 HandlerExceptionResolver 接口, Spring MVC 自带的异常解析器 SimpleMappingExceptionResolver 供开发者在 web 应用上下文配置异常映射,可在配置中注册异常解析器.

defaultError 默认错误.

要统一处理, @ControllerAdvice

@ControllerAdvice
public class ExceptionHandlingAdvice {

    @ExceptionHandler
    public String handleDefault(Exception e){
        return "error";
    }
    
    @ExceptionHandler(SomeConcreteException.class)
    public String handle(SomeConcreteException ex){
        return "concrete ex";
    }
}

1.Spring boot 2 示例:

@RestController
@RequestMapping("/books")
public class RequestController {

  @GetMapping
  public Iterable<Boolean> list() {
    return List.of();
  }

  @GetMapping("/{isbn}")
  public ResponseEntity<Book> get(@PathVariable("isbn") String isbn) {
    return new ResponseEntity<Book>(new Book(), HttpStatus.OK);
  }

  @PostMapping
  public ResponseEntity<Book> create(@RequestBody Book book, UriComponentsBuilder uriBuilder) {
    Book created = book;
    URI newBookUri = uriBuilder.path("/books/{isbn}").build(created.getIsbn());
    return ResponseEntity.created(newBookUri).body(created);
  }
}

2.常用的表单对象,Angular FormData, Spring 表单对象 POJO , 实现 Serializable


 


 汇总: request , response

@RestController
@RequestMapping("/datapro")
@CrossOrigin
public class SummaryController {

    //---- 常用 -----
    /**
     * 1. 简单表单对象, POJO, 前端框架构建的变量名要保持一致
     * validation.Errors,  validation.BindingResult
     * 如果后带, 出现异常将抛出 MethodArgumentNotValidException.
     *
     */
    @PostMapping
    public String join(@Valid UserRegistration userRegistration,                       BindResult validation){
        return "";
    }

    /**
     * 复杂表单对象,POJO 定义。包含 Part 或 Multipart, 或它们的集合
     * 不常用的带有 文件的请求参数获取
    http://xxxx/form/upload?userName=King
*/ @PostMapping("form/upload") public String upload(@RequestParam("userName") String userName, @RequestPart("upload") Part upload){ return "不常用"; } @PostMapping("form/multiPart") public String uploadMulti(@RequestParam("userName")String userName, @RequestPart("uploads")List<MultipartFile> uploads){ return ";"; } @PostMapping("form/uploads") public void uploads(UploadForm uploadForm){ } private class UploadForm{ private String userName; private List<Part> uploads; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public List<Part> getUploads() { return uploads; } public void setUploads(List<Part> uploads) { this.uploads = uploads; } } /** * 2.@RequestBody Restful 前端发送的JSON 请求正文, 可包含二进制,base64 等客户端或服务器可理解的格式. * 该数据表示某种对象时,被引用为请求实体, 或 HTTP实体. * @RequestBody 将让 Spring 自动把一个请求实体转换为控制器方法参数 * * Spring 的 HTTP 消息转换器将自动对请求实体转换。 请求实体必须得用,能理解 JSON 二进制等和 * 目标格式 POJO 或其他复杂对象的消息转换器。 */ // @Valid 触发内容验证,在POJO valid 注解。 可指定 Error 或 BindingResult 参数(可选) // 若未使用二者,验证失败将抛出 MethodArgumentNotValidExpression 异常. @PostMapping public String update(@Valid @RequestBody Account account, BindResult validation){ return ".."; } // 普通类型 // @PathVariable("") long userId // 模板变量, pattern, @PathVariable // @MatrixVariable @GetMapping("user/{userId") public String user(@PathVariable("userId") long userId){ return ""; } @GetMapping("user/{userId:\\d+}") // 限定 public void userId(@PathVariable("userId") long userId){} // 打包所有模板变量 @GetMapping("foo/{var1}/bar/{var2}") public String barFoo(@PathVariable Map<String,String> variables){ return ""; } @GetMapping("foo/{hotelId:\\d+}/guest") private void guestForm(@PathVariable("hotelId") long hotelId, @MatrixVariable(pathVar = "hotelId", value="floor") short floorNumber, @MatrixVariable(pathVar = "hotelId", value="room") short roomNumber){ return; } //----------------------- /** * xx/home/requestParamLimit/?employee=xx,confirm=true * 请求参数限定了 confirm=true 。而 employee 可不限制值,但必须存在 * @return */ @RequestMapping(value="requestParamLimit",params = {"employee","confirm=true"}) public String requestParamLimit_demo(){ return "request limit demo"; } /** * Servlet API 相关的参数类型作为参数, 其值永不为null * HttpServletRequest 请求属性, HttpServletResponse, 操作响应 * HttpSession 用于操作Http 会话对象 * InputStream / Reader 用于读取请求正文,不能同时使用. !!! 完成处理后不要关闭该对象. * OutputStream / Writer 用于编写响应正文,不能同时使用。 !!! 完成处理后不要关闭该对象. * Spring WebRequest 用于请求属性 + Http 会话对象的操作, 不需直接使用 ServletAPI,不要 * 与 HttpServlet -- Req, Res, Session 参数类型同时使用 */ @PostMapping(value="/regression/attachment") public String uploadFormObj(Upload upload){ String result = ""; result = "ok"; return result; } // 注解请求参数 /** * String, Class ,File, Local, Pattern, java.util.Pattern, java.util.Properties, java.net.URL * 以上类型,或数据或集合. * 可在Spring 注册自定义的 java.bean.PropertyEditor 或 sp.fm.core.convert.converter... 来处理. */ @RequestMapping("user") public String user(@RequestParam("id") long userId, @RequestParam(value="name", required = false) String name, @RequestParam(value="default",defaultValue = "")String key){ return ""; } /** * @RequestParam * Map<String,String) 或 spring 的 MultiValueMap<String,String> */ /** * @RequestHeader 类似与 @RequestParam。 可配合 HttpHeader 来用 */ @RequestMapping("headerInfo") public String foo(@RequestHeader("Content-Type") String contentType, Date customerHeader){ return ""; } @RequestMapping("bar") public String bar(@RequestHeader MultiValueMap<String,String> headers){ return ""; } @RequestMapping("baz") public String baz(@RequestHeader HttpHeaders headers){ return ""; }

<Spring 5 recieps> p106 

感谢参考:

1.https://blog.csdn.net/feyehong/article/details/128514631

 

1. controller 类上 注解@SessionAttributes("reservation")    // 其内还可以是 类型 , someObj.class , 数组形式。

2.controller 方法入 Model model 方法入参必须有,在方法内 model.addAttribute("reservation", new object());

3.controller 其他方法入参 @ModelAttribute("reservation" ) reservation, 

4.BindingResult 对象包含了用户新提交的数据,  result.hasError()

5.注意: 入参 SessionStatus status.setComplete() , 可将对象从 HttpSession 中移除.

   note: 只能清除与之匹配的数据,原生Session 的无法清除

   note: 只能清除当前页面的匹配的数据,如果 重定向到其他页面,在其他页面调用 SessionStatus.setComplete() 方法无法清空,只能使用原生Session api 清空.

@RestController
@RequestMapping("/statusRequest")
@SessionAttributes("SessionAttrs")
public class StatusWithMVC {

    @PostMapping("upload")
    public String handleUpload(HttpServletRequest httpServletRequest,
                               Model model, BindingResult bindingResult,
                               SessionStatus sessionStatus){

        // 原生 Session
        HttpSession session = httpServletRequest.getSession();
        if(session.getAttribute("SessionAttrs") == null){
            Map<String,Object> userData = Map.of("k1",new Object(),
                    "k2",new Object());
            session.setAttribute("SessionAttrs",userData);
        }
        
        // Model
        model.addAttribute("SessionAttrs",new Object());

        //
        if(false){
            sessionStatus.setComplete();
        }
    }

    @GetMapping("dataRetrieval")
    public String retrievalData(@ModelAttribute("SessionAttrs") Object sessionAttrs,
                                BindingResult bindingResult,
                                SessionStatus sessionStatus,
                                HttpServletRequest httpServletRequest){
        // get the data from session
        Object sessionGet = sessionAttrs;

        // 必须在当前页面,如果发生重定向,则该方法无法清除
        sessionStatus.setComplete();
        // 如果发生重定向,要清除则需要使用原生 Session
        httpServletRequest.removeAttribute("SessionAttrs");
        
        return "some";
    }
}


valid

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>8.0.0.Final</version>
</dependency>
@RestController
@RequestMapping("valid")
public class ValidController {
    
    @PostMapping
    public String submitForm(
        @ModelAttribute("reservation") @Valid Reservation reservation,
                BindingResult result,SessionStatus status){
        if(result.hasErrors()){
            return "reservationForm";
        }else{
            reservation.make("some");
            return "demo";
        }
    }
}
public class Reservation {

    @NotNull
    @Size(min = 4)
    private String courtName;

    public void make(String some){ }
}

注意:一个表单用 表单对象上传,

带上 @RequestBody 有问题:

 

@RequestPart(" 字段 “) Multipart var,  可取到部分文件.

 


2023-03-14

跨域,例如 前端 Angular 与 后端独立的 project 分离. 会话不共享.

1.cridental 前后端添加属性

2.改分离为统一


2023-05-06 

背景:

1. 项目 platform user config 向后端传递用户设定数据. 包含 string 和 object 的复杂对象。FormData 键值对 值接受的类型为 string 或 blog 文件对象。复杂对象需要额外复杂处理.

2. user config 初始值是后端传递过来的,JSON 序列化抽象类或接口无碍,这些数据不可变对象,或是Builder 模式.  无法直接反序列化.


 

 

解决:

1.采用直接的 Angular HttpClient post

注意:

1>.前端:要将数据 JSON.stringify( object ), 赋予 const body : string;  设置httpHeader content-type

2>.后端:controlller 方法中 @RequestBody ConfigVO configVO 要加上注解。联想到 httpClient 的设定 body


2. 解决:后端原始的不可变对象无法构建 无参构造函数.

解决:

项目最终采用 ViewObject 作为传递. builder 构建复杂的缘故。

注意与前端的字面量对应起来:

1. @JsonCreator 用在静态方法或构造方法,不可在实例方法上(实例方法在对象构造后).

2.@ConstructorProperties 只能在构造函数。


 

posted @ 2023-02-23 21:41  君子之行  阅读(13)  评论(0)    收藏  举报