今日内容
零、 复习昨日
零、 复习昨日
1 maven项目编译后代码在target
2 发现代码都没有错,该写的都有,但是已启动服务器404,查看target,如果编译会后资源不全面,那就删除重新编译
3 重新看一下,如何使用mavne创建javaweb项目
一、参数绑定 【重点】
所谓参数绑定,就是前端发请求中的数据,可以直接在Controller的方法参数中接收.
即前端请求数据和后端方法参数绑定.
1.1 基本类型参数绑定[重点]
基本类型指,常用的几种类型: 基本类型+String+Date
前端页面
<h2>基本类型数据绑定</h2>
<a href="/base.do?id=1&username=张三&score=10.0">请求携带数据-基本类型</a>
<hr>
<form action="/base.do" method="get">
id<input type="text" name="id"><br>
username<input type="text" name="username"><br>
score<input type="text" name="score"><br>
birthday<input type="text" name="birthday"><br>
<input type="submit" value="基本类型">
</form>
后端接收
@Controller
public class DataController {
/**
* 基本类型自动封装
* 要求是: 前端请求的参数名,后端方法的参数名要一致
* 【特殊的】 日期,前端发送的日期格式如果是yyyy-MM-dd,springmvc无法默认绑定参数,
* springmvc默认支持yyyy/MM/dd
* 两种方案解决:
* 1. 前端改,发出的日期格式就是yyyy/MM/dd即可
* 2. 后端改,给日期参数加@DateTimeFormat(pattern = "yyyy-MM-dd")
*/
@RequestMapping("/base")
public String base(int id, String username, double score, @DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday){
System.out.println("id = " + id);
System.out.println("username = " + username);
System.out.println("score = " + score);
System.out.println("birthday = " + birthday);
return "ok";
}
}
1.2 对象[重点]
场景: 注册/添加/更新
实体类
public class User {
private int id;
private String username;
private String password;
private double score;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
// setget
}
前端
<h2>对象数据绑定</h2>
<form action="/obj.do" method="get">
id<input type="text" name="id"><br>
username<input type="text" name="username"><br>
score<input type="text" name="score"><br>
birthday<input type="date" name="birthday"><br>
<input type="submit" value="对象类型">
</form>
后端
/**
* 自动绑定: 要求前端的请求中的参数要和对象的属性名一致
*/
@RequestMapping("/obj")
public String obj(User user){
System.out.println("user = " + user);
return "ok";
}
1.3 数组
场景: 批量删除需要同时接收多个id, (前端是复选框的)
前端
<h2>数组绑定</h2>
<form action="/array.do" method="get">
<input type="checkbox" name="ids" value="1">1
<input type="checkbox" name="ids" value="2">2
<input type="checkbox" name="ids" value="3">3
<input type="checkbox" name="ids" value="4">4
<input type="submit" value="数组类型">
</form>
后端
/**
* 自动绑定: 要求前端的请求中的参数要和方法参数名(数组名)一致
*/
@RequestMapping("/array")
public String array(int[] ids){
System.out.println("ids = " + Arrays.toString(ids));
return "ok";
}
1.4 List集合
List集合使用场景与数组是一样的
前端
<h2>List绑定</h2>
<form action="/list.do" method="get">
<input type="checkbox" name="skill" value="Java">Java
<input type="checkbox" name="skill" value="HTML">HTML
<input type="checkbox" name="skill" value="Linux">Linux
<input type="submit" value="List类型">
</form>
SpringMVC默认是不支持直接封装List的,解决方案
- 加注解@RequestParam,就可以【推荐】
- 间接的封装List — 创建一个实体类,定义List属性
方案一
@RequestMapping("/list")
public String list(@RequestParam List<String> skill){
System.out.println("skill = " + skill);
return "ok";
}
方案二
public class User {
private int id;
private String username;
private double score;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
private List<String> skill; // 定义集合属性
// setget
}
@RequestMapping("/list")
// 在封装对象数据时,封装list
public String list(User user){
System.out.println("user-skill = " + user.getSkill());
return "ok";
}
1.5 Map集合
Map是键值对,键和值一一映射.
跟Java对象很类似,属性和属性值一一对应.
所以什么时候需要/可以使用Map来接收参数?
- 凡是可以用对象接收的都可以使用Map
- 需要接收两个参数时,可以map
SpringMVC默认不支持直接将参数封装进Map,需要使用@RequestParam
前端
<h2>Map绑定</h2>
<form action="/map.do" method="get">
id<input type="text" name="id"><br>
username<input type="text" name="username"><br>
score<input type="text" name="score"><br>
birthday<input type="date" name="birthday"><br>
<input type="submit" value="Map类型">
</form>
<h2>模糊查询-Map绑定</h2>
<form action="/map.do" method="get">
address<input type="text" name="address"><br>
floor<input type="text" name="floor"><br>
deco<input type="text" name="deco"><br>
<input type="submit" value="模糊-Map类型">
</form>
name就是map的key
输入框的值就是map的value
后台
@RequestMapping("/map")
public String map(@RequestParam Map<String,Object> map){
System.out.println("map = " + map);
return "ok";
}
1.6 @RequestParam
当封装数据失败时使用该注解,该注解放在参数上
场景一:
前端参数和后端方法参数要一致才能封装数据,当不一致时可以使用@RequestParam来手动指定前端数据封装给参数
场景二:
默认情况下,后端方法的参数列表一旦设置了该参数,就必须传值,不传值就会报错
但是设置@RequestParam(required = false)时就可以不用传值也不报错
场景三:
当后端参数没有传值时,赋值默认值@RequestParam(defaultValue = “666666”)
二、数据乱码
之前自己写过全局编码格式拦截器
现在springmvc提供了编码格式拦截器,直接用即可
<!-- 编码格式拦截器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
三、页面跳转
之前学过的servlet中跳转页面的功能
- 请求转发:
- forward
- req.getDispatcherServlet().forward(req,resp)
- 请求路径不变
- 是服务器内部请求
- 一次请求
- 请求域的数据可以共享
- 重定向
- redirect
- resp.sendRedirect();
- 请求路径改变
- 是浏览器行为
- 两次请求
- 请求域的不能共享
请求转发
注意: 默认在使用就是请求转发
在Controller的方法的返回值中写forward:路径即可完成跳转
例如: forward:/view/ok.html forward:/test.do
注意: 跳转后的路径要写完整
/**
* 演示请求转发至其他页面
* @return
*/
@RequestMapping("/forward")
public String forward(){
System.out.println("执行请求转发" );
return "forward:/view/ok.html";
}
/**
* 演示请求转发至其他请求
* @return
*/
@RequestMapping("/forward2")
public String forward2(){
System.out.println("执行请求转发" );
return "forward:/test.do";
}
重定向
在Controller的方法的返回值中写redirect:路径即可完成跳转
例如: redirect:/view/ok.html redirect:/test.do
注意: 跳转后的路径要写完整
/**
* 演示重定向至其他页面
* @return
*/
@RequestMapping("/redirect")
public String redirect(){
System.out.println("执行重定向" );
return "redirect:/view/ok.html";
}
/**
* 演示重定向至其他请求
* @return
*/
@RequestMapping("/redirect2")
public String redirect2(){
System.out.println("执行重定向" );
return "redirect:/test.do";
}
其他的请求转发和重定向的特点和之前学习的servlet是一样的,复习.
四、数据共享
数据共享是指: 数据域,即
- request域
- 只有在一次请求中有效,即请求转发后能取出
- session域
- 一次会话有效,只要会话不结束,无论请求转发还是重定向都能取出
package com.qf.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 演示域对象(Request,Session)
*/
@Controller
public class ScopeController {
@RequestMapping("/req")
public String requestAndSession(HttpServletRequest request, HttpSession session) {
// 存入
request.setAttribute("req","req-Value");
session.setAttribute("se","se-Value");
return "forward:/req2.do";
}
@RequestMapping("/req2")
public String requestAndSession2(HttpServletRequest request, HttpSession session) {
// 取出
String v1 = (String) request.getAttribute("req");
System.out.println("v1 = " + v1);
String v2 = (String) session.getAttribute("se");
System.out.println("v2 = " + v2);
return "ok";
}
}
五、静态资源处理
目前,前端控制器(DispatcherServlet)类映射的是==*.do==,前端的静态资源例如:html,js,css,图片 等都是不影响加载的
但是,如果前端控制器(DispatcherServlet)类映射的是==/==,那就是所有请求都要经过前端控制器,静态资源也不例外. 那么此时静态资源是无法完成映射.
此时就需要静态资源处理!!!
web.xml文件
<!-- 前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 此处要改成 / ,这样才能映射匹配到所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
项目中定义一个css文件夹,定义一个css文件,在index.jsp页面中引入静态资源css,查看效果即可
springmvc.xml文件
<!-- 静态资源映射
mapping="访问路径"
location="本地资源位置"
"/**" 前端的任何请求去匹配后台处于"/"下的静态资源
-->
<mvc:resources mapping="/**" location="/"/>
ps:
<mvc:default-servlet-handler/> 也行
六、拦截器 【重点】
6.1 作用
- 之前用来做编码格式过滤
- 登录认证
- 等等
6.2 定义拦截器
- 自定义类
- 实现接口
- 重写方法
- springmvc.xml配置
package com.qf.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @desc 拦截器类
*/
public class MyInterceptor implements HandlerInterceptor {
/**
* 目前Controller,执行前,执行拦截
* 一般用于: 校验
* @return 返回true,即认为放行,返回false不放行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前 pre" );
// 写项目时,这里通过数据判断,来决定是返回true放行,还是返回false不放行
return true;
}
/**
* 在目标Controller方法执行完,但是afterCompletion方法前执行
* 对目标方法的返回再处理,可以对响应再定制.
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("post" );
}
/**
* 目标Controller的方法全部执行完执行
* 一般: 资源回收
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("after" );
}
}
以上方法是按需重写,一般来说用的是前置方法preHandle()
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- mapping path: 要拦截的路径 -->
<!-- <mvc:mapping path="/user/**"/>-->
<mvc:mapping path="/**"/>
<!-- exclude-mapping 排除拦截的 -->
<mvc:exclude-mapping path="/login"/>
<mvc:exclude-mapping path="/test.do"/>
<!-- 指定拦截器类 -->
<bean class="com.qf.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
七、异常处理
以前处理异常
- 抛出
- 视图捕获
全靠自己在每个方法中处理异常
springmvc框架提供了一个全局的异常处理机制,可以处理Controller的所有异常
这种方法,集中管理异常
- 建类
- 实现接口
- 重写方法
- 配置
@Component // 配置到spring容器
public class MyExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView mv = new ModelAndView( );
if (ex instanceof ArithmeticException) {
mv.setViewName("redirect:/view/500.html");
} else if (ex instanceof AuthException) {
mv.setViewName("redirect:/view/auth.html");
}
return mv;
}
}
测试
后台Controller抛出异常,测试!
任务
重点: 参数绑定- 重复
删除数据发请求-接收
添加/注册/更新 -> 接收
批量删除 --> 接收
其中使用的注解要会
------------------------
重新整合spring和mybatis
--------------------------------------
思考:
写项目后端数据如何在页面展现?
方案1: 存储域,在jsp页面取值
方案2: 不用jsp,用html开发,后端数据如何给前端展现?