springboot搭建web,Spring boot(4) web開發(2) 請求處理、響應處理、模板引擎

 2023-10-15 阅读 28 评论 0

摘要:參照教程:https://www.bilibili.com/video/BV19K4y1L7MT 1.請求映射 1.1 rest使用與原理 1.1.1 使用 springboot搭建web,Rest風格支持(使用HTTP請求方式動詞來表示對資源的操作) 以前:/getUser 獲取用戶 /deleteUser 刪除用戶 /editUser 修改用

參照教程:https://www.bilibili.com/video/BV19K4y1L7MT

1.請求映射

1.1 rest使用與原理

1.1.1 使用

  • springboot搭建web,Rest風格支持(使用HTTP請求方式動詞來表示對資源的操作

    • 以前:/getUser 獲取用戶 /deleteUser 刪除用戶 /editUser 修改用戶 /saveUser 保存用戶
    • 現在: /user GET-獲取用戶 DELETE-刪除用戶 PUT-修改用戶 POST-保存用戶
    • 核心Filter;HiddenHttpMethodFilter
      • 用法: 表單method=post,隱藏域 _method=put

      • springboot web項目、SpringBoot中手動開啟

        spring:mvc:hiddenmethod:filter:enabled: true
        

Controller:

@RestController
public class HelloController {@GetMapping("/user")public String getUser(){return "GET-張三";}@PostMapping("/user")public String saveUser(){return "POST-張三";}@PutMapping("/user")public String putUser(){return "PUT-張三";}@DeleteMapping("/user")public String deleteUser(){return "DELETE-張三";}}

springboot開發網站,測試頁面:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>測試</title>
</head>
<body>
<h1>測試REST風格</h1>
<form method="post" action="/user"><input type="submit" value="POST"></form>
<form method="get" action="/user"><input type="submit" value="GET"></form>
<form method="post" action="/user"><input type="hidden" name="_method" value="put"><input type="submit" value="PUT">
</form>
<form method="post" action="/user"><input type="hidden" name="_method" value="delete"><input type="submit" value="DELETE">
</form>
</body>
</html>

自定義把_method 這個名字換成我們自己喜歡的:自定義HiddenHttpMethodFilter

@Configuration
public class WebConfiguration {@Beanpublic HiddenHttpMethodFilter hiddenHttpMethodFilter(){HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();hiddenHttpMethodFilter.setMethodParam("_m");return hiddenHttpMethodFilter;}
}

1.1.2 原理

Rest原理(表單提交要使用REST的時候)

  • 表單提交會帶上**_method=PUT**

  • 請求過來被HiddenHttpMethodFilter攔截

    • 請求是否正常,并且是POST
      • 獲取到**_method**的值。
      • 兼容以下請求;PUT.DELETE.PATCH
      • 原生request(post),包裝模式requesWrapper重寫了getMethod方法,返回的是傳入的值。
      • 過濾器鏈放行的時候用wrapper。以后的方法調用getMethod是調用requesWrapper的.
  • 為什么需要手動開啟,以及可以自己配置HiddenHttpMethodFilter?

    image-20210326174110420

  • 為什么攔截的是_method?

    image-20210326174206453

  • 為什么表單請求方式需要是POST?

    image-20210326174244317

Rest使用客戶端工具,

  • 如PostMan直接發送Put、delete等方式請求,無需Filter

1.2 請求映射原理

image-20210327150427520

FrameworkServlet繼承HttpServlet并重寫了doGet()方法:

image-20210327151143876

而doGet()最終還是要執行processRequest()這個方法,而processRequest()內部的核心方法是doService():

image-20210327151404101

doService()是一個抽象方法:

protected abstract void doService(HttpServletRequest var1, HttpServletResponse var2) throws Exception;

在DispatcherServlet中有doService()的實現,而doService()中的核心是調用本類的doDispatch()方法,所以研究doDispatch()方法是最終的方法

image-20210327151903771

對Spring MVC功能分析從DispatcherServlet的doDispatch()方法開始:

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {try {ModelAndView mv = null;Object dispatchException = null;try {processedRequest = this.checkMultipart(request);multipartRequestParsed = processedRequest != request;//找到當前請求使用哪個Handler(Controller的方法)處理mappedHandler = this.getHandler(processedRequest);//HandlerMapping:處理器映射。/xxx->>xxxx

打斷點,發送請求并進入這個方法:

image-20210327153510015

可以看到,這個方法內部是將所有的handlerMappings用迭代器進行匹配:

image-20210327153846429

這些handlerMappings有(index頁發送的是Get請求):

image-20210327153939530

進入第一個mapping,我們可以看到RequestMapping中有我們在控制器寫的各種處理請求的方法

image-20210327154242191

進入getHandler()方法,可以看到調用了getHandlerInternal()來處理:

image-20210327155346034

進入getHandlerInternal()方法,可以看到調用了父類的getHandlerInternal()方法,再次打斷點

image-20210327160505114

在這個方法里再進行找路徑以及請求方法:

image-20210327161218650

總結:所有的請求映射都在HandlerMapping中。

  • SpringBoot自動配置歡迎頁的 WelcomePageHandlerMapping 。訪問 /能訪問到index.html;

  • SpringBoot自動配置了默認 的 RequestMappingHandlerMapping

  • 請求進來,挨個嘗試所有的HandlerMapping看是否有請求信息。

    • 如果有就找到這個請求對應的handler
    • 如果沒有就是下一個 HandlerMapping
  • 我們需要一些自定義的映射處理,我們也可以自己給容器中放HandlerMapping。自定義 HandlerMapping

2.普通參數與基本注解

2.1 注解

@PathVariable、@RequesHeader

 @GetMapping("/car/id/{id}/owner/{owner}")public Map<String, Object> getCar(@PathVariable("id") Integer id,@PathVariable("owner") String owner,@PathVariable Map<String, String> kv,@RequestHeader("host") String host,@RequestHeader Map<String, String> headers){Map map = new HashMap();map.put("id", id);map.put("owner", owner);map.put("kv", kv);map.put("host", host);map.put("headers", headers);return map;}//前端頁面:<a href="/car/id/11/owner/lisi">測試@PathVariable和@RequestHeader</a><br/>

@RequestParam、@CookieValue

  @GetMapping("/person")public Map<String, Object> getInfo(@RequestParam("id") Integer id, @RequestParam Map<String, String> info,@CookieValue("_ga") Cookie cookie, @CookieValue("_ga") String _ga){Map map = new HashMap();map.put("id", id);map.put("info", info);System.out.println(cookie.getName() + "---->");return map;}//<a href="/person?id=12&username=zhangsan&age=18">測試@RequestParam</a><br/>

@RequestBody

post方法請求才有請求體:

 @PostMapping("/save")public Map postMethod(@RequestBody String content){Map<String,Object> map = new HashMap<>();map.put("content",content);return map;}<form action="/save" method="post">姓名: <input type="text" name="username"><br/>密碼: <input type="text" name="password"><br/><input type="submit" value="submit">
</form>

@RequestAttribute

獲取請求域的值

@Controller
public class RequestTestController {@GetMapping("/goto")public String goToPage(HttpServletRequest request){request.setAttribute("username", "zhangsan");request.setAttribute("password", 1234567);return "forward:/success";}@ResponseBody@GetMapping("/success")public Map success(@RequestAttribute("username") String username,@RequestAttribute("password") Integer password,HttpServletRequest request){Map map = new HashMap();map.put("username", username);map.put("password", password);map.put("username_re", request.getAttribute("username"));map.put("password_re", request.getAttribute("password"));return map;}
}

@MatrixVariable與UrlPathHelper

矩陣變量:

image-20210329094035390

配置:

@Configuration
public class WebConfiguration implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {UrlPathHelper urlPathHelper = new UrlPathHelper();urlPathHelper.setRemoveSemicolonContent(false);configurer.setUrlPathHelper(urlPathHelper);}
}

或者:

@Configuration
public class WebConfiguration{@Beanpublic WebMvcConfigurer webMvcConfigurer(){return new WebMvcConfigurer(){@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {UrlPathHelper urlPathHelper = new UrlPathHelper();urlPathHelper.setRemoveSemicolonContent(false);configurer.setUrlPathHelper(urlPathHelper);}};}
}

測試:

  //1、語法: 請求路徑:/cars/sell;low=34;brand=byd,audi,yd//2、SpringBoot默認是禁用了矩陣變量的功能//      手動開啟:原理。對于路徑的處理。UrlPathHelper進行解析。//              removeSemicolonContent(移除分號內容)支持矩陣變量的//3、矩陣變量必須有url路徑變量才能被解析@GetMapping("/cars/{path}/{info}")public Map carsSell(@MatrixVariable("low") Integer low,@MatrixVariable("brand") List<String> brand,@PathVariable("path") String path,@MatrixVariable("price") Integer price){Map<String,Object> map = new HashMap<>();map.put("low",low);map.put("brand",brand);map.put("path",path);map.put("price", price);return map;}// /boss/1;age=20/2;age=10@GetMapping("/boss/{bossId}/{empId}")public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,@MatrixVariable(value = "age",pathVar = "empId") Integer empAge){Map<String,Object> map = new HashMap<>();map.put("bossAge",bossAge);map.put("empAge",empAge);return map;}

2.2 Servlet API

WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId

2.3 復雜參數

Map、**Model(map、model里面的數據會被放在request的請求域 request.setAttribute)、**Errors/BindingResult、RedirectAttributes( 重定向攜帶數據)ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder

Map<String,Object> map,  Model model, HttpServletRequest request 都是可以給request域中放數據,
request.getAttribute();

2.4 自定義參數

可以自動類型轉換與格式化,可以級聯封裝。

/***     姓名: <input name="userName"/> <br/>*     年齡: <input name="age"/> <br/>*     生日: <input name="birth"/> <br/>*     寵物姓名:<input name="pet.name"/><br/>*     寵物年齡:<input name="pet.age"/>*/
@Data
public class Person {private String userName;private Integer age;private Date birth;private Pet pet;}@Data
public class Pet {private String name;private String age;}

自定義converter

    //1、WebMvcConfigurer定制化SpringMVC的功能@Beanpublic WebMvcConfigurer webMvcConfigurer(){return new WebMvcConfigurer() {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {UrlPathHelper urlPathHelper = new UrlPathHelper();// 不移除;后面的內容。矩陣變量功能就可以生效urlPathHelper.setRemoveSemicolonContent(false);configurer.setUrlPathHelper(urlPathHelper);}@Overridepublic void addFormatters(FormatterRegistry registry) {registry.addConverter(new Converter<String, Pet>() {@Overridepublic Pet convert(String source) {// 啊貓,3if(!StringUtils.isEmpty(source)){Pet pet = new Pet();String[] split = source.split(",");pet.setName(split[0]);pet.setAge(Integer.parseInt(split[1]));return pet;}return null;}});}};}

3.響應處理

3.1 響應json

jackson.jar+@ResponseBody

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
web場景自動引入了json場景<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId><version>2.3.4.RELEASE</version><scope>compile</scope></dependency>

給前端自動返回json數據

    @ResponseBody@GetMapping("/pet")public Pet getPet(Pet pet){return pet;}<form action="/pet" method="get">姓名:<input type="text" name="name" value="cat"><br/>年齡:<input type="text" name="age" value="18"><br/><input type="submit" value="submit">
</form>

支持的返回值類型

ModelAndView
Model
View
ResponseEntity 
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且為對象類型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;

3.2 內容協商

根據客戶端接收能力不同,返回不同媒體類型的數據

3.2.1 引入xml依賴

 <dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId>
</dependency>

3.2.2 使用postman測試接受不同類型的數據

只需要改變請求頭中Accept字段。Http協議中規定的,告訴服務器本客戶端可以接收的數據類型。

xml:

image-20210330154019413

json:

image-20210330154101972

4.模板引擎thymeleaf

4.1 thymeleaf簡介

Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text.

現代化、服務端Java模板引擎

4.2 基本語法

1.表達式

image-20210330155332259

2.字面量

  • 文本值: ‘one text’ , ‘Another one!’ **,…**數字: 0 , 34 , 3.0 , 12.3 **,…**布爾值: true , false

  • 空值: null

  • 變量: one,two,… 變量不能有空格

3.文本操作

  • 字符串拼接: +
  • 變量替換: |The name is ${name}|

4.數學運算

運算符: + , - , * , / , %

5.布爾運算

運算符: and , or

一元運算: ! , not

6.比較運算

比較: > , < , >= , <= ( gt , lt , ge , le **)**等式: == , != ( eq , ne )

7.條件運算

If-then: (if) ? (then)

If-then-else: (if) ? (then) : (else)

Default: (value) ?: (defaultvalue)

8.特殊操作

無操作: _

4.3 設置屬性值-th:attr

設置單個值

<form action="subscribe.html" th:attr="action=@{/subscribe}"><fieldset><input type="text" name="email" /><input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/></fieldset>
</form>

設置多個值

<img src="../../images/gtvglogo.png"  th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />

替代寫法:

<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>
<form action="subscribe.html" th:action="@{/subscribe}">

4.4 迭代

<tr th:each="prod : ${prods}"><td th:text="${prod.name}">Onions</td><td th:text="${prod.price}">2.41</td><td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'"><td th:text="${prod.name}">Onions</td><td th:text="${prod.price}">2.41</td><td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>

4.5 條件運算

<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
<div th:switch="${user.role}"><p th:case="'admin'">User is an administrator</p><p th:case="#{roles.manager}">User is a manager</p><p th:case="*">User is some other thing</p>
</div>

4.6 屬性優先級

image-20210330180802576

4.7 thymeleaf使用

1.引入starter

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>

2.自動配好了thymeleaf

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration { }

自動配好的策略

  • 1、所有thymeleaf的配置值都在 ThymeleafProperties
  • 2、配置好了 SpringTemplateEngine
  • 3、配好了 ThymeleafViewResolver
  • 4、我們只需要直接開發頁面
	public static final String DEFAULT_PREFIX = "classpath:/templates/";public static final String DEFAULT_SUFFIX = ".html";  //xxx.html

3.頁面開發

html引入命名空間: xmlns:th=“http://www.thymeleaf.org”

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1 th:text="${msg}">哈哈</h1>
<h2><a href="www.atguigu.com" th:href="${link}">去百度</a>  <br/><a href="www.atguigu.com" th:href="@{link}">去百度2</a>
</h2>
</body>
</html>

4.8 應用

1.路徑構建

    <form class="form-signin" action="index.html" method="post" th:action="@{/login}">

這是前端登錄頁面的表格,點擊提交后會請求到相應的controller來處理:

@PostMapping("/login")public String main(User user, HttpSession session, Model model){String username = user.getUsername();String password = user.getPassword();if("deserts".equals(username) && "123".equals(password)){session.setAttribute("user", user);return "redirect:/main.html";}else{model.addAttribute("msg", "賬號或者密碼錯誤");return "login";}}@GetMapping("main.html")public String mainPage(HttpSession session, Model model){Object user = session.getAttribute("user");if (user != null){return "main";}else{model.addAttribute("msg", "請重新登錄");return "login";}}

直接寫入標簽內的文本:

 <a href="#">[[${session.user.username}]]</a> 

2.錯誤回顯

前面處理的用戶登錄的controller在用戶登錄失敗或著沒登錄直接訪問main頁面時,應該返回登錄頁及給出提示信息,通過model設置request域的值,從前端頁面取出來,達到回顯的效果

<label style="color:green;" th:text="${msg}"/>

3.抽取重復頁面

這里主要參照官網,區分三種抽取的方式。抽取的片段:

<footer th:fragment="copy">&copy; 2011 The Good Thymes Virtual Grocery
</footer

頁面引入抽取片段的三種方式:

<body>...<div th:insert="footer :: copy"></div><div th:replace="footer :: copy"></div><div th:include="footer :: copy"></div></body>

會導致的結果:

<body>...<div><footer>&copy; 2011 The Good Thymes Virtual Grocery</footer></div><footer>&copy; 2011 The Good Thymes Virtual Grocery</footer><div>&copy; 2011 The Good Thymes Virtual Grocery</div></body>

區別:insert是插入原引入標簽的內部,replace是將原標簽給替換成碎片部分的標簽和內容,include是去掉標簽將碎片內容包含在原標簽中。

4.數據渲染(遍歷)

controller:

    @GetMapping("/dynamic_table")public String dynamic_table(Model model){List<User> users = Arrays.asList(new User("aaa", "111"), new User("bbb", "222"),new User("ccc", "333"), new User("ddd", "444"));model.addAttribute("users", users);return "table/dynamic_table";}

頁面:

<table class="display table table-bordered" id="hidden-table-info"><thead><tr><th class="hidden-phone">#</th><th class="hidden-phone">用戶名</th><th class="hidden-phone">密碼</th></tr></thead><tbody><tr class="gradeX" th:each="user,status:${users}"><td class="hidden-phone" th:text="${status.count}"></td><td class="center hidden-phone">[[${user.username}]]</td><td class="center hidden-phone" th:text="${user.password}"></td></tr></tbody></table>

效果:

image-20210402101243290

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/137199.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息