学习笔记--Spring MVC
1、SpringMVC开发步骤
1)导入MVC相关坐标
2)配置SpringMVC核心控制器DispatcherServlet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!-- 配置SpringMVC前端控制器--> <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:spring-mvc.xml</param-value> </init-param> <!-- 不配置说明是访问时启动服务,配置时就是一直启动服务 数字越小优先级越高 --> <load-on-startup> 1 </load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <!-- 如果配置的是缺省的,那么说明访问所有的网址都要启动这个服务servlet --> <url-pattern>/</url-pattern> </servlet-mapping> |
这里的
1 2 3 4 | <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> |
一开始不明白,后来查阅资料后发现:
SpringMVC配置文件的默认路径是WEB-INF下面,如果你的配置文件不想放在WEB-INF目录下,则可以通过
contextConfigLocation这个初始化参数进行指定。classpath:xxx就是去resource目录下找。
3)创建Controller类和视图页面
4)使用注解配置Controller类中业务方法的映射地址
5)配置SpringMVC核心文件spring-mvc.xml(组件扫描之类的)
组件扫描必须在context命名空间下,需要自己添加设置。
1 2 3 | xmlns:context= "http://www.springframework.org/schema/context" //在xsi:schemaLocation中添加 http: //www.springframework.org/schema/context <br>http://www.springframework.org/schema/context/spring-context.xsd |
6)客户端发起请求测试
2、SpringMVC注解解析
2.1 @RequestMapping
RequestMapping用于建立请求URL和处理请求方法之间的对应关系。
简单来说就是跳转到某地址时会执行的方法。
有两种可以使用该方法的位置:
1、类上,说明请求URL的第一级访问目录。此处可以不写,就相当于应用的根目录。
2、方法上,说明请求URL的第二级访问目录,与类上使用@RequestMapping标注的一级目录一起组成访问的虚拟路径。
另外,该注解还附有3个参数:
value:用于指定请求的URL,如果只有这个参数,可以不写value
1 | @RequestMapping( "quick" ) = @RequestMapping(value = "quick" ) |
method:用于指定请求的方式,如果将值设为RequestMethod.GET说明只有Get请求可以通过。
params:用于指定限制请求参数的条件。如果params = {"accountName"} 表示请求参数必须有accountName
2.2 配置内部资源视图解析器
作用:在配置跳转视图的时候,能够简化地址
1 2 3 4 5 6 | <!-- 配置内部资源视图解析器 --> <bean id= "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > <!-- 用这个配置的,都是/jsp/xxx.jsp --> <property name= "prefix" value= "/jsp/" /> <property name= "suffix" value= ".jsp" /> </bean> |
用bean注入mvc包里的视图解析器类。这个类有prefix和suffix的set方法,可以自定义属性的值。
prefix:地址的共同前缀。
suffix:地址的共同后缀。
2.3 SpringMVC的数据响应方式
1)页面跳转
- 直接返回字符串
具体做法见2.2配置内部资源解析器
- 通过ModelAndView对象返回
ModelAndView对象返回方式的好处在于:Model是用于封装数据的,View是展示视图的。可以分离开。
有以下几种使用方式:
一、在方法内创建一个ModelAndView类
1 2 3 4 5 6 7 8 9 10 11 | @RequestMapping( "/quick2" ) public ModelAndView save2(){ /* Model: 模型 用于封装数据 View: 视图 用于展示视图 */ ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject( "username" , "xcc" ); modelAndView.setViewName( "success" ); return modelAndView; } |
addObject方法是添加数据,参数是一个键值对,前面是名称,后面的是值,不仅仅是字符串,别的数据类型都行。
setViewName方法是命名视图地址,这个地址也受内置视图解析器的影响。
二、在请求方法中写ModelAndView形参。
1 2 3 4 5 6 7 8 9 | /* 当springMVC收到这个跳转函数的时候,发现有modelandview实参,会自己创建一个注入。 */ @RequestMapping( "/quick3" ) public ModelAndView save3(ModelAndView modelAndView){ modelAndView.addObject( "username" , "xcnb" ); modelAndView.setViewName( "success" ); return modelAndView; } |
MVC识别到请求方法中有形参的时候,会自动帮你注入一个实参。
优点是避免每次手动创建一个ModelAndView对象。其余的同一。
三、model和view进行分离
1 2 3 4 5 6 7 8 | /* 这里将modelandview分开,model以参数的形式交给stringmvc处理,string以逻辑视图的方式返回。作用是一样的 */ @RequestMapping( "/quick4" ) public String save4(Model model){ model.addAttribute( "username" , "小超和你" ); return "success" ; } |
视图以字符串格式回传,model以参数形式创建。
2)回写数据
- 直接返回字符串
- 返回对象或集合
基础用法(直接返回字符串):
1 2 3 4 5 6 7 8 9 | /* responsebody是告知函数返回的字符串不是跳转而是直接在http响应体中返回 */ @RequestMapping( "/quick5" ) @ResponseBody public String save5(){ //回写字符串 return "hello xcc" ; } |
与返回跳转类似,如果不需要跳转而是回写数据的话,需要在方法上加注释@ResoponseBody
ResponseBody意思是响应体,因为方法与res.writer.print相同,是通过响应数据回传的。
更好的用法:
因为一般回传的数据都是以对象的JSon格式为主,所以,可以用第三方对象转json格式的工具。
将需要回传的数据转换成json格式后再回传。
1 2 3 4 5 6 7 8 9 10 11 | @RequestMapping( "/quick6" ) @ResponseBody public String save6() throws JsonProcessingException { User user = new User(); user.setAge( 10 ); user.setUsername( "xcc" ); //使用json的转换工具将对象转换成json格式字符串在返回 ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(user); return json; } |
json转换工具需要导 jackson-databind 依赖包
最好的用法(返回对象和集合):
刚才使用的方法是用第三方的工具包来给我们将对象转换成Json格式的字符串。
但每次都要创建一个Mapper类显得有些麻烦,MVC帮我们底层完成了这个功能。
在配置文件中,加入mvc命名空间:
1 2 3 | xmlns:mvc= "http://www.springframework.org/schema/mvc" xsi:schemaLocation="http: //www.springframework.org/schema/mvc http: //www.springframework.org/schema/mvc/spring-mvc.xsd" |
再加入以下配置:
1 | <mvc:annotation-driven/> |
这样之后,以后要取得返回的Json格式的字符串,就不必使用转换工具,直接返回该对象,处理器适配器
会自动将该对象转换成Json格式的字符串。
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* 如果想要让返回的对象是一个已经处理好的json字符串。 在spring-mvc中注入RequestMappingHandlerAdapter 向messageConverters注入MappingJackson2HttpMessageConverter 前提必须是@responsebody响应体返回 替换这个配置可以在xml中<mvc:annotation-driven/>这句注解替代 */ @RequestMapping( "/quick7" ) @ResponseBody public User save7() { User user = new User(); user.setAge( 12 ); user.setUsername( "xcc" ); return user; } |
2.4 SpringMVC获得请求数据(服务器端)
1)普通数据类型
例子:
1 2 3 4 5 6 7 8 9 10 | /* controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动匹配 */ @RequestMapping( "/quick8" ) @ResponseBody public void save8( String username, int age) { //当网址是localhost:8080/user/quick8?username=xxxx&age=xx时,会将username和age自动匹配 System.out.println(username); System.out.println(age); } |
当方法是响应体方法、且业务方法的参数名称与请求参数的名称一致时,
MVC会自动匹配参数,将值传给该参数。
2)获得POJO类型数据
例子:
1 2 3 4 5 6 7 8 | /* 获得pojo类的数据,请求参数恰好都是pojo类中的属性,会自动适配填补 */ @RequestMapping( "/quick9" ) @ResponseBody public void save9(User user) { System.out.println(user); } |
当请求参数的名称与POJO类的属性名称一致时,MVC会自动适配填补。
3)获得数组类型数据
例子:
1 2 3 4 5 6 7 8 | @RequestMapping( "/quick10" ) @ResponseBody public void save10( String [] strs) { System.out.println(Arrays.asList(strs)); //Arrays.asList() 是将数组转化成list集合的方法 //但不支持add,remove,clear方法 //遍历数组十分方便,但是如果要添加或者删除元素还是new一个list遍历添加。 } |
当请求参数的名称与数组名称一致时,MVC会自动适配填补。
4)获得集合类型参数
获得集合类型参数与别的数据略有不同,需要将集合放入一个VO对象,通过对VO对象的注入来获得集合类型参数。
例子:
1 2 3 4 5 6 7 8 | /* 获得集合类型的数据,是将集合放在pojo类中实现,然后传入pojo类,名称对应 */ @RequestMapping( "/quick11" ) @ResponseBody public void save11(VO vo) { System.out.println(vo); } |
在方法中,和获得POJO类型的数据类似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class VO { private List<User> userList; public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this .userList = userList; } @Override public String toString() { return "VO{" + "userList=" + userList + '}' ; } } |
VO对象中,将需要注入的集合加入成员属性中。
1 2 3 4 5 6 7 8 9 | <body> <form action= "${pageContext.request.contextPath}/user/quick11" method= "post" > <input type= "text" name= "userList[0].username" ><br/> <input type= "text" name= "userList[0].age" ><br/> <input type= "text" name= "userList[1].username" ><br/> <input type= "text" name= "userList[1].age" ><br/> <input type= "submit" value= "提交" > </form> </body> |
在页面中,将要注入的集合中的某一对象的什么元素对应,MVC就会自动填充属性。
5)获得集合类型参数Ⅱ
当使用ajax提交数据时,可以指定contextT为json格式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而无需使用POJO进行包装。
1 2 3 4 5 6 7 8 9 10 11 12 | <script src= "${pageContext.request.contextPath}/js/jquery-3.6.0.js" ></script> <script> let userList = []; userList.push({username: "zhansan" ,age: 18 }); userList.push({username: "lisi" ,age: 20 }); $.ajax({ type: "Post" , url: "${pageContext.request.contextPath}/user/quick12" , data:JSON.stringify(userList), contentType: "application/json;charset=utf-8" }) </script> |
1 2 3 4 5 | @RequestMapping( "/quick12" ) @ResponseBody public void save12(@RequestBody List<User> userList) { System.out.println(userList); } |
光是这样并不能找到jquery-3.6.0.js,因为之前在MVC配置中,DispatcherServlet的映射配置是缺省的,这意味着所有的地址请求
都要走这个Servlet,而在ajax请求前,先申请导入了jquery的资源文件,但这个并不能被RequestMapping映射找到,所以就略过不处理,这就导致了
其实jquery根本没有被导入。
解决方法1:
在Spring-mvc.xml中开放资源的访问。
1 2 | <!-- 开放资源的访问 mapping是访问的地址格式、后面的是具体所在的目录--> <mvc:resources mapping= "/js/**" location= "/js/" /> |
解决方法2:
在Spring-mvc.xml中使用默认的处理器
1 2 | <!-- 功能是当mvc找不到对应的servlet时用原始的处理器(tomcat)处理 --> <mvc: default -servlet-handler/> |
2.5 Post请求中如果出现乱码该如何解决
可以配置一个filter过滤器,将所有代码格式全部变为UTF-8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!-- 配置全局过滤的filter --> <filter> <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
同样的<init-param>起到一个设置过滤器编码格式的作用。
2.6 参数绑定注解@requestParam
作用:当请求参数与需要的参数名称不一致,但仍想对应起来时,可以使用该注解配置value参数进行映射。
1 2 3 4 5 6 | @RequestMapping( "/quick13" ) @ResponseBody public void save13(@RequestParam( "name" ) String username ,@RequestParam( "age" ) String nianling) { System.out.println(username); System.out.println(nianling); } |
即:将请求地址为“http://localhost:8080/user/quick13?name=zhangsan&age=18” 依然可以对应注入参数。
补充:
@RequestParam有其他几个参数
required:默认为true,说明请求地址时必须包含此参数。
defaultValue: 当没有指定请求参数时,则使用指定的默认值赋值。
2.7 获得Restful风格的参数
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件。
基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP协议里面四个表示操作方式的动词如下:
GET:获取资源
POST:新建资源
PUT:更新资源
DELETE:删除资源
示例:
1 2 3 4 5 6 | //访问localhost:8080/user/quick14/zhangsan 最后不同的 username 回传的参数也不同 @RequestMapping( "/quick14/{username}" ) @ResponseBody public void save14(@PathVariable(value = "username" ) String username) { System.out.println(username); } |
用 @PathVariable 注解来将占位符和参数绑定,value和{}中的属性要保持一致。
2.8 自定义类型转换器
客户端请求的任何数据到达服务端之后都会变成字符串。
但客户端发送的关于数字的请求依然可以正常的访问,说明MVC内部有将数字(int)转换成字符串的方法。
但不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。
自定义类型转换器的开发步骤:
1)定义转换器类实现Converter接口(复写接口的方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class DateConverter implements Converter< String , Date > { @Override public Date convert( String s) { // new 里面是样式 SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" ); Date date = null ; try { date = format.parse(s); } catch (ParseException e) { e.printStackTrace(); } return date; } } |
2)在配置文件中声明转换器。
1 2 3 4 5 6 7 | <bean id= "conversionService" class = "org.springframework.context.support.ConversionServiceFactoryBean" > <property name= "converters" > <list> <bean class = "com.xc.converter.DateConverter" /> </list> </property> </bean> |
3)在<annotation-driven>中引用转换器
1 | <mvc:annotation-driven conversion-service= "conversionService" /> |
当遇到指定格式的时候,就会自动使用转换器。
2.9获得Servlet相关API
SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:
HttpServletRequest
HttpServletResponse
HttpSession
1 2 3 4 5 6 7 | @RequestMapping( "/quick16" ) @ResponseBody public void save16(HttpServletRequest request, HttpServletResponse response, HttpSession session) { System.out.println(request); System.out.println(response); System.out.println(session); } |
2.10 获得请求头
1)@RequestHeader
使用@RequestHeader可以获得请求头信息。
注解属性如下:
value:请求头的名称
required:是否必须携带此请求头
1 2 3 4 5 | @RequestMapping( "/quick17" ) @ResponseBody public void save17(@RequestHeader(value = "User-Agent" , required = false ) String user_agent) { System.out.println(user_agent); } |
2)@CookieValue
使用@CookieValue可以获得指定Cookie的值
注解属性如下:
value:指定Cookie的名称
required:是否必须携带此Cookie
1 2 3 4 5 | @RequestMapping( "/quick18" ) @ResponseBody public void save18(@CookieValue(value = "JSESSIONID" ) String jsessionId) { System.out.println(jsessionId); } |
2.11 文件上传
1)文件上传客户端三要素
表单项type=“file”
表单的提交方式是post
表单的enctype属性是多部分表单形式,即enctype="multipart/form-data"
1 2 3 4 5 | <form action= "${pageContext.request.contextPath}/user/quick19" enctype= "multipart/form-data" > 名称<input type= "text" name= "username" ><br/> 文件<input type= "file" name= "upload" ><br/> <input type= "button" value= "上传" > </form> |
2) 用MVC实现单文件上传
导入fileupload和io坐标
1 2 3 4 5 6 7 8 9 10 11 | <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version> 1.3 . 3 </version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version> 2.6 </version> </dependency> |
配置文件上传解析器
1 2 3 4 5 | <!-- 配置文件上传解析器 --> <bean id= "multipartResolver" class = "org.springframework.web.multipart.commons.CommonsMultipartResolver" > <property name= "defaultEncoding" value= "UTF-8" /> <property name= "maxUploadSize" value= "500000" /> </bean> |
单文件上传的业务方法
1 2 3 4 5 6 7 8 9 | @RequestMapping( "/quick19" ) @ResponseBody public void save19( String username, MultipartFile uploadFile) throws IOException { System.out.println(username); //System.out.println(uploadFile); //获得上传文件的名称 String originalFilename = uploadFile.getOriginalFilename(); uploadFile.transferTo( new File( "D:\\upload\\" +originalFilename)); } |
transferTo方法将接受到的上传文件以相同文件的格式保存在服务器端。
2.12 多文件上传
大致与单文件一致,但是业务方法接收时改用数组
1 2 3 4 5 6 7 8 9 | @RequestMapping( "/quick20" ) @ResponseBody public void save20( String username, MultipartFile[] uploadFile) throws IOException { System.out.println(username); for (MultipartFile multipartFile : uploadFile) { String originalFilename = multipartFile.getOriginalFilename(); multipartFile.transferTo( new File( "D:\\upload\\" +originalFilename)); } } |
1 2 3 4 5 6 | <form action= "${pageContext.request.contextPath}/user/quick20" method= "post" enctype= "multipart/form-data" > 名称<input type= "text" name= "username" ><br/> 文件<input type= "file" name= "uploadFile" ><br/> 文件<input type= "file" name= "uploadFile" ><br/> <input type= "submit" value= "上传" > </form> |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?