SpringMVC - 学习笔记
文章目录
SpringMVC
1. 初识SrpingMVC
ssm:spring+springmvc+mybatis MVC三层架构
Spring:IOC 和 AOP
SpringMVC:SpringMVC的执行流程!
MVC:模型(dao,service),视图(jsp),控制器(Servlet)
-
pojo:实体类,如User
-
vo:视图层的对象实体类,如UserVo
-
dto:数据传输的时候的对象实体类,如UserDto
SpringMVC特点:
- 轻量级,简单易学
- 高效,基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定优于配置
- 功能强大:RESTful,数据验证,格式化,本地化,主题等
- 简洁灵活
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring2.5开始,使用java5或以上版本的用户可以采用注解的controller声明方式
快速入门:
-
在web.xml配置
<!--注册DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联一个springmvc配置文件:springmvc-servlet.xml--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> <!--启动级别1--> <load-on-startup>1</load-on-startup> </servlet> <!--/ 匹配所有的请求:(不包括.jsp)--> <!--/* 匹配所有的请求:(包括.jsp)--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
新建一个配置文件spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--处理器映射器--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--处理器适配器--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!--视图解析器:DispatcherServlet给他的ModelAndView--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> </beans>
-
写一个Controller类
public class HelloController implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //ModelAndView 模型和视图 ModelAndView mv = new ModelAndView(); // 封装对象,放在ModelAndView中 mv.addObject("msg","HelloSpringMVC!"); // 封装要跳转的视图,放在ModelAndView中 mv.setViewName("hello"); return mv; } }
-
编辑配置文件spring-mvc.xml,将Controller类放入IOC中
<bean id="/hello" class="cn.codewei.controller.HelloController"/>
-
编写jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${pageContext.request.getAttribute("msg")} </body> </html>
可能遇到的问题:访问出现404,排查步骤:
-
查看控制台输出,看一下是不是缺少了什么jar包
-
如果jar包存在,显示无法输出,就在IDEA项目结构中,添加lib依赖
-
重启tomcat,即可解决
2. SpringMVC执行原理
实际开发中,我们不会这么去做,我们一般通过注解来实现!!
3. 使用注解实现SpringMVC
-
在web.xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>springmvc</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> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
在springmvc.xml中配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--自动扫描包,让指定包下的注解生效,由IOC统一管理--> <context:component-scan base-package="cn.codewei.controller"/> <!--让springmvc不再处理静态资源--> <mvc:default-servlet-handler/> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射 要想使@RequestMapping生效 必须向上下文注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理 而annotation-driver配置帮助我们自动完成上述两个实例的注入 --> <mvc:annotation-driven/> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> </beans>
在视图解析器中我们把所有视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问
-
编写一个Controller类
@Controller //代表这个类会被springIOC托管,被这个注解的类中的所有方法,如果返回值是String,并且由具体的页面可以跳转,那么就会被视图解析器解析 @RequestMapping("/hello") public class HelloController { @RequestMapping("/controllerhello") public String Controllerhello(Model model){ // 封装数据 model.addAttribute("msg","HelloSrpingMVC!"); return "hello"; // 被视图解析器处理 } }
SpringMVC必须配置的三大件:
处理器映射器,处理器适配器,视图解析器
实现接口Controller定义控制器是较老的办法
缺点是:一个控制器只有一个方法,如果要多个方法则需要定义多个Controller
@Component 组件
@Service serivce层
@Controller controller层
@Repository dao层
4. RestFul风格
RestFul就是一个资源定位及资源操作的风格,不是标准也不是协议,只是一种风格
使用RestFul操作资源:可以通过不同的请求方式来实现不同的效果!
如下:请求地址一样,但是功能可能不同
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE
原来的:http://localhost:8080/add?a=2&b=3
RestFul:http://http://localhost:8080/add/1/2
在SpringMVC中可以使用@PathVariable注解,让方法参数的值对应绑定到一个URI模板变量上
@Controller
public class RestFulController {
@RequestMapping("/add/{a}/{b}")
public String test(@PathVariable int a,@PathVariable int b, Model model){
int result = a +b;
model.addAttribute("msg","执行了add方法!"+result);
return "login";
}
}
可以通过设置method来设置请求的的方式,如只能通过GET方式访问的到:
@Controller
public class RestFulController {
@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
public String test(@PathVariable int a,@PathVariable int b, Model model){
int result = a +b;
model.addAttribute("msg","执行了add方法!"+result);
return "login";
}
}
可是使用注解来设置允许请求的方式,如
@Controller
public class RestFulController {
@GetMapping("/add/{a}/{b}")
public String test(@PathVariable int a,@PathVariable int b, Model model){
int result = a +b;
model.addAttribute("msg","执行了add方法!"+result);
return "login";
}
}
@GetMapping(“/add/{a}/{b}”)
@PostMapping(“…”)
@DeleteMapping(“…”)
@PutMapping(“…”)
通过设置访问方式的约束,可以来实现通过相同的URL,不同的访问方式,得到的访问结果是不同的
5. 重定向和转发
结果跳转方式:
页面:{视图解析器前缀}+名字{视图解析器后缀}
方式一:可能通过原生的HttpServletRequest request, HttpServletResponse response的形式
@Controller
public class ModelTest1 {
@GetMapping("/modelTest1")
public String test1(HttpServletRequest request, HttpServletResponse response){
request.setAttribute("msg","helloModelTest1!");
return "test";
}
}
方式二:不再配置视图解析器
-
删除springmvc.xml中的配置
<!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean>
-
通过return 来实现转发或重定向
@Controller public class ResultSpringMVC{ @RequestMapping("/rsm/t1") public String test1(){ // 转发 return "/index.jsp"; } @RequestMapping("/rsm/t2") public String test2(){ // 转发二 return "forward:/index.jsp"; } @RequestMapping("/rsm/t3") public String test3(){ // 重定向 return "redirect:/index.jsp"; } }
方式三:有视图解析器时,转发和重定向(经常使用)
在有视图解析器时,转发,直接写转发到的文件的名字,重定向,加上前缀,写上路径,如
return "redirect:/index.jsp"; //重定向
return "index"; // 转发
6. 接收请求参数及数据回显
6.1 处理提交数据
1. 提交的参数名称和处理方法的参数名一致
如:localhost:8080/hello?name=codewei
处理方法:
@RequestMapping("/hello")
public String hello(String name){
...;
return "...";
}
2. 提交的参数名和处理的参数名不一致
如:localhost:8080/hello?username=codewei
处理方法:
@RequestMapping("/hello")
public String hello(@RequestParam("usermae") String name){
...;
return "...";
}
3. 提交的是一个对象
如:localhost:8080/hello?name=codewei&id=1&age=20
封装成一个实体类
public class User {
private int id;
private String name;
private int age;
...;
}
处理方法
@Controller
public class UserControllerTest {
@RequestMapping("/user")
public String userTest(User user, Model model){
model.addAttribute("user",user);
return "login";
}
}
6.2 数据回显到前端
方式一:通过ModelAndView
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
String result = "HelloSpringMVC!";
mv.addObject("msg",result);
mv.setViewName("test");
return mv;
}
}
方式二:通过Model(通常使用Mode)
@Controller
public class UserControllerTest {
@RequestMapping("/user")
public String userTest(User user, Model model){
model.addAttribute("user",user);
return "login";
}
}
方式三:通过ModelMap
继承了LinkedMap的方法和特性,和Model用法基本一样
LinkedHashMap–>ModelMap–>Model
7. 乱码问题解决
可以解决过滤器Filter解决
@WebFilter("/*")
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
public void destroy() {
}
}
使用springmvc,我们可以不再像之前一样写Filter过滤器类了,我们可以直接在web.xml配置
<!--配置过滤器:utf-8-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
JSON乱码问题解决:
可通过注解@RequestMapping中的一个参数进行设置,如
@RequestMapping(value="/j1",produces="application/json;charset=utf-8")
但是我们一般不会这么做
我们在spring-mvc.xml中的mvc:annotation-driven中进行配置
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
9. 补充
@ResponseBody // 它就不会走视图解析器,会直接返回一个字符串
@Controller
public class UserController {
@ResponseBody // 它就不会走视图解析器,会直接返回一个字符串
public String json1(){
return "test";
}
}
这样return就是单纯的返回一个字符串
@RestController //放在类上,该类下所有方法只会返回JSON字符串,不会走视图解析器
@Controller
@RestController // 该类下所有方法只会返回JSON字符串,不会走视图解析器**
public class UserController {
@GetMapping("/j1")
public String json1() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = new User(1,"唐嫣",33);
String s = objectMapper.writeValueAsString(user);
return s;
}
}
Json工具类
public class JsonUtils {
// json工具类 获取json
public static String getJson(Object object){
return getJson(object,"yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object,String dateFormat){
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
获取json
public static String getJson(Object object){
return getJson(object,"yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object,String dateFormat){
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
10. 拦截器
-
自定义拦截器类,就必须实现HandlerInterceptor接口
public class MyInterceptor implements HandlerInterceptor { // return true;放行 执行下一个拦截器 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("=====处理前==========="); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("============处理后============"); } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("===========清理=========="); } }
-
在springmvc.xml中配置拦截器
<mvc:interceptors> <mvc:interceptor> <!--包括这个请求下面的所有请求--> <mvc:mapping path="/**"/> <bean class="cn.codewei.config.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
11. 文件上传
在前端页面要设置表单中的enctype属性
- application/x-www=form-urlencode:默认方式,只处理表单域中的value属性值,采用这种编码方式的表单会将表单域中的值处理成URL编码方式
- multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符集编码
- text/plain:除了把空格转换为"+"号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件
1. 导入jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2. 配置
SpringMVC为文件上传提供了直接的支持,这种支持是即插即用的MultipartResolver实现的
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--请求编码格式,必须和jsp的pageEncoding一致-->
<property name="defaultEncoding" value="utf-8"/>
<!--上传文件大小限制 单位为字节-->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
3. 上传文件:方式一
@RestController
public class FileController {
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
// 获取文件名
String filename = file.getOriginalFilename();
// 如果文件为空,直接回到首页
if ("".equals(filename)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名:" + filename);
// 上传路径保存设置
String path = request.getRealPath("/upload");
// 如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:" + realPath);
InputStream is = file.getInputStream(); // 文件输入流
FileOutputStream os = new FileOutputStream(new File(realPath, filename)); //文件输出流
// 读取写出
int len=0;
byte[] bytes = new byte[1024];
while((len =is.read(bytes))!=-1){
os.write(bytes,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp"
}
}
4. 上传文件:方式二
@RestController
public class FileController {
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
// 上传路径保存设置
String path = request.getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
// 通过CommonsMultipartFile的方法直接写文件
file.transferTo(new File(realPath+"/"+file.getOriginalFilename()));
return "redirect:/index.jsp";
}
}