Spring Controller 基本认识及应用

举报
yumuing 发表于 2023/06/21 18:12:18 2023/06/21
【摘要】 注:本文是以前初学时期的笔记上传,如有错误,还望指出,一定改正,谢谢支持!有兴趣也可以关注我的博客:[yumuing 博客](https://yumuing.top/) ## Controller 相关介绍 Controller 在 spring 中代表的是控制层,是将访问者请求进行分发调用不同函数,来控制获取请求参数以及返回业务层处理完的数据给访问者的层面。它在 spring 中必须在 Co

👏 Hi! 我是 Yumuing,一个技术的敲钟人

👨‍💻 每天分享技术文章,永远做技术的朝拜者

📚 欢迎关注我的博客:Yumuing’s blog

注:本文是以前初学时期的笔记上传,如有错误,还望指出,一定改正,谢谢支持!有兴趣也可以关注我的博客:yumuing 博客

Controller 相关介绍

Controller 在 spring 中代表的是控制层,是将访问者请求进行分发调用不同函数,来控制获取请求参数以及返回业务层处理完的数据给访问者的层面。它在 spring 中必须在 Controller 类前添加 @Controller 注解,以注入容器中,并发挥作用。

在 Controller 中存在两种传递参数的方式,第一种是采用路径后添加 ? 参数的方式,第二种则是采用参数直接写入路径的方式,如下:

第一种:yumuing/params?username=yumuing&password=1234

第二种:yumuing/user/{userId}

在 Get 请求中,获取第一种参数的方式,主要是利用 @RequestParam 这个注解得到同名的参数,获取第二种参数的方式则是采用 @PathVariable 这个注解获取 @RequestMapping 中的大括号标记的同名参数,其中,@RequestParam 和 @PathVariable 都是作为方法参数书写的,必须注明参数类型(如 String ),@RequestMapping 则是方法整体注解,在添加新参数时,路径得使用 path 进行指定,而不是一个简单的字符串书写即可,来如下:

//第一种
@RequestMappingpath="/params",method=RequestMethod.GETpath = {"/params"},method = {RequestMethod.GET}path="/params",method=RequestMethod.GET
public void params@RequestParam(name="username",required=false,defaultValue="test"@RequestParam(name = "username", required = false,defaultValue = "test"@RequestParam(name="username",required=false,defaultValue="test"String username);
//第二种
@RequestMappingpath="/user/userId",method=RequestMethod.GETpath = "/user/{userId}",method = {RequestMethod.GET}path="/user/userId",method=RequestMethod.GET
public void params@PathVariable("userId"@PathVariable("userId"@PathVariable("userId" int userId);

当然,@RequestMapping 的参数还有很多,但必须注意的一点是尽可能使用 大括号(即 {},会更加直观,也防止部分一定要求需要大括号的参数出错,并且这个注解既可以一个函数,也可以注解一个类。当注解一个类时,类中所有的方法都会在这个基础上再进行过滤,参数类型基本包括如下:

  • path:路径参数,书写格式参照 url 后缀格式的字符串(即 ”/yumuing/user“ )参数指定了访问该方法的具体路径,不指定参数名时,默认为填写内容为 path 的参数内容,path也可以是一个未定的变量。
  • method:访问方法参数,主要包括 Get(RequestMethod.GET)、Post(RequestMethod.POST)、Delete(RequestMethod.DELETE)、Put(RequestMethod.PUT)等等,都是调用的方式进行填写的。
  • params:请求参数,不可与 RequestParam 中的参数重复定义,会发生冲突,没有优先级之分。书写格式为字符串,如 ”yumuing“

根据以上三个参数,我们就能够让一个 controller 通过请求 url、参数、访问方法来进行区分并处理对应请求,并分别调用不同的函数,返回所需结果。

如果,想要在浏览器中进行简单的打印验证,可以考虑在对应 Controller 函数前添加 @RequestBody,并指定返回参数为 String ,它将会只打印返回的 String 数据,而不去进行渲染等等操作。如果,不使用 @RequestBody 即默认返回 HTML 数据。

当然,@RequestBody 也可以作为函数参数在将方法指定为只能使用 Post 请求之后,只接受请求体内容。与其不同的 @RequestParam,则是接收并解析请求体中以 key-value 格式的数据。两者可以同时使用,也可单独使用。

//打印示例
@RequestMapping("/hello")
@ResponseBody
public String hello() {
    return "hello";
}

返回的结果基本分为两种,一是数据,二是模板,数据可以是一个简单的 int 类型,也可以是 json 类型,乃至其他类型,而模板即是传递给浏览器渲染的 jsp、html 等等格式的内容。

在 thymeleaf 中,模板文件默认放在 resources/templates 中,可以存在子目录。模板文件基本配置如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <!-- xmlns:th="http://www.thymeleaf.org"设置读取该模板文件 -->
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
 	<!--具体内容  -->
    <!-- 示例内容 -->
     <p th:text="${name}"></p>
     <p th:text="${age}"></p>
    <!-- th:text="${age}"匹配对应内容 -->
</body>
</html>

最终响应到浏览器的模板数据如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
  <p>hhhh</p>
  <p>30</p>
</body>
</html>

Controller 访问模板文件示例:

@RequestMapping(path = "/test",method = RequestMethod.GET)
public ModelAndView test(){
    ModelAndView mav = new ModelAndView();
    mav.addObject("name","hhh");
    mav.addObject("age",30);
    mav.setViewName("/demo/view");
    return mav;
}

@RequestMapping(path = "/test02",method = RequestMethod.GET)
public String test02(Model model){
    model.addAttribute("name","hhhh");
    model.addAttribute("age",30);
    return "/demo/view";
}

第一种是将 model 和 view 数据都装一个对象里,最后把两者一起返回,而第二种是将 model 放到参数里,把模板文件返回。从代码阅读来看,第二种更为简洁直观,更推荐使用。注意第一种使用的是 addObject(),第二种用的是 addAttrubute(),两种不可混用,并且注意第一种返回数据为 ModelAndView ,第二种返回数据为 String,当然,如果函数参数没有携带 org.springframework.ui.Model 的对象,将不会被识别为返回模板文件,而是返回字符串。

接下来,我们就介绍 json 数据是该怎么样去通过 Controller 传输的。它基本是发生在一次异步请求中的,也就是说,每次请求数据,返回模板数据,而是返回 json 数据,以浏览器更新已有的模板文件,不会导致每次请求的数据量传输过大,影响用户体验。

thymeleaf 模板引擎配合下,Controller 只添加 @RequestMapping 注解默认传输模板文件,当添加 @ResponseBody 后,我们就能传输 json 数据,当然,返回数据类型不能是 String 类型,否则,就只会打印,而不会转成 json 格式数据,并打印出来了。如下:

@RequestMapping(path = "/emp",method = RequestMethod.GET)
@ResponseBody
public Map<String,Object> getEmp(){
    Map<String,Object> emp = new HashMap<>();
    emp.put("name","张三");
    emp.put("age",16);
    emp.put("code",778522);
    return emp;
}

访问 localhost:8888/yumuing/emp ,返回数据并打印在浏览器数据如下:

{"code":778522,"name":"张三","age":16}

bug 总结

请求参数定义多次,无法访问

屏幕截图_20230203_212649

出现原因:

  • 在 @RequestMapping 中已经定义 params,又在 @RequestParam 中定义 params,导致出现错误。
  • 如果参数前写了@RequestParam(xxx),并且没有添加 require = false ,那么前端必须有对应的xxx名字才行,不然,就会发生错误。
  • @RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。否则也会发生错误。
  • 访问静态文件时,路径为放置在 resource/static 目录下的相对路径,如 test.html 文件在/resourse/static/html/test.html,路径即为 localhost:端口号/html/test.html,除非配置了全局url 前缀。

错误效果如下:

访问页面显示

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Fri Feb 03 21:33:35 HKT 2023
There was an unexpected error (type=Bad Request, status=400).

控制台输出

2023-02-03T21:33:35.418+08:00  INFO 24684 --- [nio-8888-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-02-03T21:33:35.418+08:00  INFO 24684 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-02-03T21:33:35.418+08:00  INFO 24684 --- [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
2023-02-03T21:33:35.430+08:00  WARN 24684 --- [nio-8888-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.UnsatisfiedServletRequestParameterException: Parameter conditions "username, password" not met for actual request parameters: ]
 

解决方案:

  • 第一种:删去 @RequestMapping 中多余的定义即可。
  • 第二种:要么添加 require = false ,要么请求添加对应参数,要么后端不加该参数
  • 第三种:使用 Post 请求,或者删去这个注解
  • 第四种:书写正确路径即可

注:System.out.printf() 为控制台输出,return、HttpServletResponse等等都是页面输出。

找不到模板文件

控制台报错:

Error resolving template template might not exist or might not be accessible;

解决方案:

  • 修改 application.yml 文件中的配置为:

    保证能够读取 html 文件,注意前有一英文半角 ”点“ ,设置 cache 为不缓存,保证实时修改,实时生效,生产环境推荐,方便调试,部署环境改为缓存型。设置文件路径,/templates 后不要加斜杆。

    spring:
      thymeleaf:
        suffix: .html
        encoding: utf-8
        mode: HTML5
        cache: false
        prefix: classpath:/template
    
  • 修改 Controller 函数访问模板路径为为相对路径,如:/demo/view ,记得最前面有斜杠,最后面没有斜杠,不需要写后缀名,默认 html

本文测试代码均在我的博客 Spring Controller 基本认识及应用获取

求点赞转发

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。