雪一更--软件开发--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 只能在构造函数。


浙公网安备 33010602011771号