在Spring MVC中,Handler是一个用来处理HTTP请求的对象。它通常是一个控制器(Controller)类中的方法。当用户发送一个请求到服务器时,Spring MVC会根据请求的URL、HTTP方法等信息,找到相应的处理器(Handler)来处理这个请求。
简而言之,Spring MVC中的Handler就是负责处理特定HTTP请求的组件,通常是一个控制器方法。它的作用是根据请求的内容执行相应的业务逻辑,并返回适当的响应。
这个过程确保了请求能够根据配置和注解映射到合适的控制器方法,进而处理用户的请求并返回结果。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
我们使用handler之前,首先需要再pom.xml中引入依赖,“spring-boot-starter-web”,他实际上还是在JavaWeb开发的范畴,所以我们需要引入Spring MVC框架。
Handler的参数列表,功能非常强大,主要功能有以下两点:
//http://localhost:8080/login?username=kobe&password=123
@RequestMapping("/login")
public void login(String username, String password){
System.out.println(username);
System.out.println(password);
}
//http://localhost:8080/login?name=kobe1&age=23&birthday=2020-02-02
@RequestMapping("/login")
public void login(Person person) {
System.out.println(person.getName());
System.out.println(person.getAge());
}
public class User {
private String username;
private String password;
@DateTimeFormat(pattern = "yyyy-MM-dd")//前端到后端 可以把前端string类型转换到后端date类型
//@JsonFormat(pattern = "yyyy-MM-dd")//后端到前端 可以把后端date类型转换到前端string
private Date birthday;
// getters & setters...
}
http://localhost:8080/delSel?ids=1&ids=2 请求参数ids为方法的参数
@RequestMapping("delSel")
public String delSel(Integer[] ids) {
System.out.println(Arrays.toString(ids));
return "index";
}
//http://localhost:8080/delSel?ids=1&ids=2
@RequestMapping("delSel")
public String delSel(List<Integer> ids) {
System.out.println(ids);
return "index";
}
//不可以,因为方法参数中的数据类型 必须是可实例化的,得有构造方法,List是个接口,没办法构造。但是可以使用ArrayList
//http://localhost:8080/delSel?ids=1&ids=2
@RequestMapping("delSel")
public String delSel(@RequestParam ArrayList<Integer> ids) {
System.out.println(ids);
return "index";
}
//但是必须在参数前面加@RequestParam才可以拿到请求参数
可以在Handler的形参中直接使用以下类型:
HttpServletRequest
HttpServletResponse
HttpSession
@RequestMapping("servletTest")
public void servletTest(
HttpServletRequest request,
HttpServletResponse response,
HttpSession session
) throws IOException
{
System.out.println(request.getContextPath());
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("网页中文内容");
System.out.println(session.getId());
}
可以为Handler指定两种种返回值类型:
void
如果返回值为void
的时候,可以在Handler形参上定义request
和response,使用
request 或
response指定响应结果
String
逻辑视图名称
返回的字符串就是逻辑视图。
@RequestMapping("login2")
public void login2(HttpServletRequest request, HttpServletResponse response) throws IOException {
String username = request.getParameter("username");
System.out.println(username);
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("返回值");
}
@RequestMapping("/login3")
public String login3() {
//return "forward:/login1";//可以请求转发到另一个handler
//return "forward:/index.jsp";//可以请求转发到另一个jsp
return "redirect:/index.jsp";//可以重定向到另一个jsp 注意观察地址栏
}
@RequestMapping
//@RequestMapping(value = "/login1")
//@RequestMapping(path = "/login1")
//@RequestMapping(value = {"/login1", "/login2"})
@RequestMapping(value = "login1",method = RequestMethod.GET)//只有get请求才可以 post请求进不来
public String login(Person person) {
return "index";
}
- 通过`value`属性配置该方法的访问路径
- 通过method属性指定该方法允许的访问方式
@Controller
@RequestMapping("/test")
public class TestController1 {
@RequestMapping("/test1")//test1方法的请求路径变为//http://localhost:8080/test/test1
public String test1() {
System.out.println("Hello SpringMvc test1");
return "index";//返回的就是逻辑视图 请求转发到index.jsp 地址栏没变
}
窄化请求,可以对请求URL进行分类管理,例如:`/person/add`、`/person/list`……
@RequestParam
该注解用来标注一个请求参数:
在方法的形参前,可以加可以不加,加了就有特殊含义了
@RequestMapping(value = "/login3")
public String login3(String name) {
System.out.println(name);
return "index";
}
//上述方式在请求 login3 可以不强制传递请求参数,那打印name结果是null
@RequestMapping(value = "/login3")
public String login3(@RequestParam String name) {
System.out.println(name);
return "index";
}
//http://localhost:8080/login3?name=tom
//上述方式在请求 login3 强制必须传递请求参数,那打印name结果就是请求参数传的值
//http://localhost:8080/login3?name1=tom
@RequestMapping(value = "/login3")
public String login3(@RequestParam("name1") String name) {
System.out.println(name);
return "index";
}
//上述方式在请求 login3 的请求参数是name1 指定请求参数的名字
//@RequestParam(value = "name1") 和 @RequestParam(name = "name1") 等同于 @RequestParam("name1")
//http://localhost:8080/login3
@RequestMapping(value = "/login3")
public String login3(@RequestParam(name = "name1", required = false) String name) {
System.out.println(name);
return "index";
}
//required = false,默认是true 代表着必须传递参数,如果设置false代表可以不传递参数
@RequestMapping(value = "/login3")
public String login3(@RequestParam(name = "name1",defaultValue = "zs") String name) {
System.out.println(name);
return "index";
}
//设置默认值,这样required就不需要在写了。
public String login(@RequestParam(value = "username", required = true, defaultValue = "noname") String name)
value
:@RequestParam(value="username")
等同于@RequestParam("username")
,对应请求参数的键
required
:参数是否必填
defaultValue
:设置默认值
@PathVariable
将路径的一部分作为请求参数,RESTful的基础。
//http://localhost:8080/findById/1
@RequestMapping("/findById/{id}")
public String findById(@PathVariable Integer id) {
System.out.println(id);
return "index";
}
//请求参数就不可以是?号。参数必须是目录形式。
RESTful就是一个url的编写风格。使用RESTful就不需要用?问号分割请求参数了。
一个严格的RESTful中是不可能存在?的。
一个URl对应一个资源,请求方式确定一个动作。
springboot中放置静态资源的目录,常用有static和templates目录,只要把静态资源放到这几个目录下,就能直接访问到。
static目录下静态资源默认是可以被访问到的,但是templates目录下资源默认是访问不到的,需要做配置:
spring.web.resources.static-locations=classpath:/templates
也可以直接给所有静态资源添加一个前缀,既可统一拦截,又可统一放开
spring.mvc.static-path-pattern=/res/**
http://localhost:8080/res/login1.html
Spring MVC对JSON的⽀持⾮常友好,主要⽤到两个注解:@RequestBody,@ResponseBody
也可以配置为其它的JSON⼯具,⽐如fastjson,⾃学如何配置。
为什么学习Jackson,因为它是SpringMVC默认的,方便配置使用。
public class User {
private Integer id;
private String username;
private String password;
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
c
head>
<body>
<button id="btn1">发送jsonbutton>
<button id="btn2">接收jsonbutton>
body>
<script>
$('#btn1').click(function () {
$.ajax({
url: "/login",
type: 'post',
data: '{"username":"zs","password":"20"}',
contentType: 'application/json'
});
});
//在jquery的ajax中,如果没加contentType:"application/json",那么data就应该对应的是json对象。
//反之,如果加了contentType:"application/json",那么ajax发送的就必须是字符串。
//状态码:415, 表示服务器无法处理请求的媒体格式。
//状态码:400,前端传的参数类型或者名称与后台接收参数的实体类的属性类型或者名称不一致,或者后端要一个参数,但是前端没传递
script>
html>
Handler部分
@Controller
public class JsonController {
@PostMapping("/login")
public String login(@RequestBody User user) {
System.out.println(user);
return "redirect:/index.html";
}
}
测试:查看控制台是否接受到前端发送过来的json数据。
JavaScript部分
<script>
$('#btn2').click(function () {
$.ajax({
url: "/findAll",
type: 'get',
success:function (res){
console.log(res)
}
});
})
script>
Handler部分
@GetMapping("/findAll")
@ResponseBody
public List<User> findAll() {
List<User> list = new ArrayList<>();
User user = new User();
user.setId(1);
user.setUsername("码上未来");
user.setPassword("codingfuture");
list.add(user);
return list;
}
测试:查看前端页面console页面,是否拿到后端响应过来的数据。
注意:@ResponseBody 注解一定要放在方法上面,标注,不要放到方法返回值处标注。
@ResponseBody 注解也可以放到类上,这样该类内部每个方法都会隐式被标注为@ResponseBody。
FormData
@PostMapping("/person/add")
@ResponseBody
public String add(String username, String password){
System.out.println(username);
System.out.println(password);
return "ok";
}
<script>
let params = new FormData();
params.append("username", "admin");
params.append("password", "123456");
$('#send').click(function () {
console.log("发送数据")
$.ajax({
url: '/person/add',
type: 'post',
data: params,
contentType: false,
processData: false,
});
});
script>
JavaWeb拦截器(Interceptor)是一种在Web应用程序中用于拦截并处理请求和响应的机制。它在请求到达控制器之前或响应返回给客户端之前执行,通常用于实现如认证、日志记录、性能监控等横切关注点(cross-cutting concerns)。拦截器的主要特点包括:
在Spring框架中,拦截器通常通过实现HandlerInterceptor接口来定义,其中包括preHandle、postHandle、afterCompletion三个方法,分别用于处理请求前、请求后和请求完成后的逻辑。
实现HandlerInterceptor
接口
/**
* 创建拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
//该方法在handler处理请求之前被调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//return true;//拦截失败 通过
return false;//拦截成功,不通过
}
//该方法在当前handler处理之后,也就是Controller方法被调用之后执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
}
// 在页面渲染之后进行处理
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
}
}
//将配置注入容器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
//拦截所有资源
.addPathPatterns("/**")
//将指定资源放行
.excludePathPatterns("/index.html", "/login","/js/**");
}
}
public class LoginInterceptor implements HandlerInterceptor {
/**
* 在接口调用前 执行
*
* @param request
* @param response
* @param handler
* @return true 放行 不拦截 否则...
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
HttpSession session = request.getSession();
Object username = session.getAttribute("username");
if (username != null) {
//放行
return true;
}
Map<String, Object> map = new HashMap<>();
map.put("code", 403);
map.put("data", "list");
map.put("message", "success");
String data = JSON.toJSONString(map);
response.getWriter().println(data);
retrn false;
}
}