Spring Boot 2.x快速上手(七)Spring Boot与Web开发
前言: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>