前言:Spring Boot幫我們簡化了架構的依賴和配置過程,但在Web開發層面上,仍然沿用Spring MVC開發的方式。
目錄
本次的學習環節依舊是採用案例的方式來進行學習的,學習的教程相關資料和視頻也是可以找到的,如果有人需要源碼和視頻資源可以去下載和學習:https://edu.51cto.com/center/course/lesson/index?id=260193
我們先導入已經下載好的源碼,然後導入到ide中;
一、Spring Boot中請求頁面
1、Spring Boot中請求頁面分爲兩種情況:
- 靜態頁面(直接放在/static目錄下,靜態頁面即可直接訪問)
- 動態頁面(需要通過Controller跳轉到動態頁面,通過下面的兩個註解進行綁定)
- @GetMapping
- @RequestMapping(value = "/",method = RequestMethod.GET)
Spring MVC 中最重要的環節就是開發Controller控制器,在WebController中添加顯示頁面的代碼:
//RequestMethod.GET 只有GET請求才能訪問這個方法,如果是Post則會提示405錯誤
@RequestMapping(value = "/",method = RequestMethod.GET)
public String index(){
return "index";
}
在application.properties文件中設置端口號爲80,緩存設置爲關閉,在啓動之前的還需要進行一下的設置,
然後啓動項目,到頁面上查看效果,
2、Controller獲取請求參數
- 請求參數
- 在方法參數前增加@RequestParam進行獲取
- 如果參數名與頁面傳遞參數相同,則可以自動匹配完成注入
- 路徑變量
- 在方法參數前增加@PathVariable獲取uri中的參數
3、Controller中向頁面傳值
Controller中向頁面傳值主要有三種方式:
- ModelAndView對象(推薦)
- Model對象
- WebRequest或者HttpServletRequest(不推薦)
//在Spring MVC中常用的設置上下文有三種:
/**
* 1、ModelAndView
* 2、Model
* 3、WebRequest或者原生的HttpServletRequest對象
*/
@RequestMapping(value = "/",method = RequestMethod.GET)
public ModelAndView index(){
ModelAndView mav = new ModelAndView("index");
mav.addObject("emps",emps);
return mav;
}
// //高內聚,低耦合的設計原則
// public String index(Model model){
// model.addAttribute("emp",emps);
// return "index";
// }
// //setAttribute是向當前的請求中放入對象,這種方式與web容器強耦合
// public String index(WebRequest req,HttpServletRequest request){
// req.setAttribute("emps",emps);
// request.setAttribute("emps",emps);
// return "index";
//
// }
4、Thymeleaf頁面取值
在Thymeleaf中,讀取Controller傳入的數據需要使用${...}表達式進行獲取。
在index.jsp頁面中做如下的修改:
<html xmlns:th="http://www.thymeleaf.org">
<tr th:each="emp,stat:${emps}">
<td th:text="${stat.index +1}"></td>
<td>[[${emp.empno}]]</td>
<td>[[${emp.ename}]]</td>
<td>[[${emp.dname}]]</td>
<td>[[${emp.job}]]</td>
<td>[[${emp.hiredate}]]</td>
<td style="color: red;font-weight: bold">[[${emp.sal}]]</td>
<td style="text-align: center">
<button class="btn btn-xs btn-info"></span>查看照片</button>
</td>
</tr>
頁面展示:
二、AJAX的應用與處理
當點擊新增按鈕時彈出如下的界面:
部門的選項我們可以進行如下的操作,
1、在WebController中創建一個新的方法:
//@RequestMapping(value = "dept",method = RequestMethod.GET)
//AJAX返回的是JSON數據,而不是跳轉頁面
@GetMapping("/dept")
//@ResponseBody代表將返回值JSON序列化後送給瀏覽器,Spring Boot默認使用的JSON序列化工具是Jackson
@ResponseBody
public List<Dept> obtainDept(){
return depts;
}
2、在index.html中進行ajax的修改操作
//點擊新增按鈕觸發
$("#btnAdd").click(function () {
//彈出對話框
$('#dlgForm').modal()
//$.ajax是jquery默認的ajax核心方法
$.ajax({
url:"/dept",
type:"get",
dateType:"json",
success:function (json) {
//接收來自服務器的json字符串,並轉換爲json對象
console.log(json);
//清空原有的option選項
$("#dept").get(0).length=0;
for(var i =0;i < json.length;i++){
var d = json[i];
//.get(0)是獲取到原生的DOM對象
//只有原生對象纔有.option屬性
$("#dept").get(0).options.add(new Option(d.dname));
}
}
})
});
崗位和部門之間是一個二級聯動,即根據部門來選擇崗位,
在WebController中添加如下的代碼進行實現:
@GetMapping("/job")
@ResponseBody
public List<String> obtainDept(String d) {
List<String> jobs = new ArrayList<String>();
jobs.add("請選擇");
if (d.equals("REASERCH")){
jobs.add("CTO");
jobs.add("Program");
}else if(d.equals("SALES")){
jobs.add("CSO");
jobs.add("saler");
}else if(d.equals("ACCOUNTING")){
jobs.add("CFO");
jobs.add("Cashier");
}
return jobs;
}
在index.html中進行ajax修改:
//二級聯動
$("#dept").change(function() {
var dept = $(this).val();//獲取當前的部門
$.ajax({
url:"/job?d="+dept,
dateType:"json",
data:"get",
success:function (json) {
//清空原有的屬性
$("#job").get(0).length = 0;
for(var i = 0;i<json.length;i++){
var job = json[i];
//.get(0)是獲取到原生的DOM對象
//只有原生對象纔有.options屬性
$("#job").get(0).options.add(new Option(job));
}
}
})
})
刷新頁面之後即可顯示級聯關係。
三、文件上傳的處理
頁面中有一個“員工照片”的上傳按鈕,即我們需要上傳一個照片文件上去,我們進行如下的代碼編寫,
在index.html中進行修改,
<!-- 網頁具備文件上傳的三個條件
1、post提交
2、form組件
3、設置表單的enctype="multipart/form-data",默認表單的enctype是x-www-urlencoding
-->
<form action="/create" method="post" enctype="multipart/form-data">
修改上傳按鈕的name屬性:name=“photo”
<input type="file" id="phone" name="photo">
在WebController中編寫文件上傳的代碼:
/**
* 文件上傳
* @param photo
* @return
*/
@PostMapping("/create")
//MultipartFile是上傳文件接口,對應了保存的臨時文件
//參數名與前端的name值保持一致
//@RequestParam("photo")代表了photo參數對應與前端name=photo的file框
public ModelAndView create(@RequestParam("photo") MultipartFile photo) throws IOException {
//String path ="E:/upload/";
String fileanme = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
String suffix = photo.getOriginalFilename().substring(photo.getOriginalFilename().lastIndexOf("."));
if(!suffix.equals(".jpg")&&!suffix.equals(".png")){
throw new RuntimeException("無效的圖片格式!");
}
//Spring提供了一個文件操作類FileCopyUtil
//對上傳文件的複製,稱爲“歸檔”。
FileCopyUtils.copy(photo.getInputStream(),new FileOutputStream(path+fileanme+suffix));
return null;
}
在application.properties文件中進行相關的設置;
#單個文件最大尺寸
spring.servlet.multipart.max-file-size=2mb
#一個請求最大的尺寸
spring.servlet.multipart.max-request-size=50mb
#自定義歸檔目錄
app.upload.location=E:/upload/
四、獲取表單數據
當我們新添加一個員工的信息的時候,就需要從前臺的表單獲取表單中的數據,
前後端的數據綁定要求所有的表單項與後臺實體bean的屬性名相同,依次按照bean實體的屬性名給前臺的表單項添加name屬性,然後在WebController中編寫獲取表單的數據:
@PostMapping("/create")
//MultipartFile是上傳文件接口,對應了保存的臨時文件
//參數名與前端的name值保持一致
//@RequestParam("photo")代表了photo參數對應與前端name=photo的file框
/**
* 前後端數據綁定,後端使用bean接收,要求屬性和前端name保持一致就可以自動注入
*/
public ModelAndView create(Emp emp,@RequestParam("photo") MultipartFile photo) throws IOException {
//String path ="E:/upload/";
String fileanme = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
String suffix = photo.getOriginalFilename().substring(photo.getOriginalFilename().lastIndexOf("."));
if(!suffix.equals(".jpg")&&!suffix.equals(".png")){
throw new RuntimeException("無效的圖片格式!");
}
emp.setPhotoFile(fileanme+suffix);
emps.add(emp);//向數據源增加一個emp對象
//Spring提供了一個文件操作類FileCopyUtil
//對上傳文件的複製,稱爲“歸檔”。
FileCopyUtils.copy(photo.getInputStream(),new FileOutputStream(path+fileanme+suffix));
//頁面重定向到localhost
//格式爲redirect:跳轉地址
ModelAndView mav = new ModelAndView("redirect:/");
return mav;
}
在此值得注意的是:需要重新創建一個ModelAndView進行頁面的重定向。
五、404、500錯誤頁面
六、註冊Filter
搭載過濾器就需要的入口類中註冊Filter,
//在入口類中註冊Filter
//@Bean會將方法中的放回對象在SB啓動的時候放入IoC容器中
@Bean
public FilterRegistrationBean filterRegiste(){
FilterRegistrationBean regFilter = new FilterRegistrationBean();
//創建並註冊AccessRecordFilter
regFilter.setFilter(new AccessRecordFilter());
//對所有請求進行攔截
regFilter.addUrlPatterns("/*");
//設置過濾器名字
regFilter.setName("AccessRecorder");
//設置排序,如果系統中有多個過濾器,Order就決定了那個過濾器就先執行,數字越小越靠前執行
regFilter.setOrder(1);
return regFilter;
}
創建一個過濾器類,
public class AccessRecordFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(AccessRecordFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String uri= request.getRequestURI();
if(uri.endsWith(".css")||uri.endsWith(".js")||uri.endsWith(".jpg")||uri.endsWith(".png")){
filterChain.doFilter(servletRequest,servletResponse);
return;
}
String ua = request.getHeader("user-agent");
String ip = request.getRemoteAddr();
Long st = new Date().getTime();
//將請求向後送到Controller進行處理
filterChain.doFilter(servletRequest,servletResponse);
Long et = new Date().getTime();
logger.info("url:{},ip:{},time:{}ms,ua:{}",uri,ip,(et-st),ua);
}
@Override
public void destroy() {
}
}
完成之後在我們的控制檯可以打印出相關的信息。
七、替換Tomcat
Spring Boot支持三種內嵌的web容器:
- Tomcat (默認),是最流行的web容器
- Jetty :性能優秀的web容器,適用於長連接
- Undertow:非阻塞web容器,性能優異,適用於高併發
在實際的開發過程中就效率來看,Jetty是完全碾壓Tomcat的,但目前來看大多的情況下還是使用Tomcat的。
替換的過程只是在pom文件中對容器的包進行修改即可,不需要其他的操作。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-jetty</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-undertow</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <artifactId>spring-boot-starter-tomcat</artifactId>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>