狂神~SpringMVC笔记

本文深入讲解SpringMVC的工作原理及其实现步骤,包括DispatcherServlet的作用、HandlerMapping与HandlerAdapter的功能、视图解析器的配置方法,同时介绍了RESTful风格的使用、重定向与转发的区别、对象接收方式以及JSON数据处理技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MVC概念

Controller:控制器 servlet层

  1. 区的表单数据
  2. 调用业务逻辑
  3. 转向指定页面

Model:模型 dao+service

  1. 业务逻辑
  2. 保存数据的状态

View:视图 jsp

  1. 显示界面

MVC框架要做哪些事情

  1. 将url映射到java类或java类的方法。
  2. 封装用户提交的数据
  3. 处理请求–调用相关的业务处理–封装响应数据。
  4. 将相应的数据进行渲染。jsp/html等表示层数据。

官方文档

https://docs.spring.io/spring-framework/docs/4.3.24.RELEASE/spring-framework-reference/

SpringMVC执行原理图 虚线为自己要实现的步骤

在这里插入图片描述

简要分析执行流程

  1. DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出的请求,DispatcherServlet接收请求并拦截请求。

    • 假设请求url为:http://localhost:8080/SpringMVC/hello

      将上url拆成三部分:

    • http://localhost:8080服务器域名

    • SpringMVC部署在服务器上的web站点

    • hello表示控制器

    • 通过分析,如上url表示为请求位于服务器localhost:8080上的SpringMVC站点的hello控制器

  2. HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。

  3. HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为: hello。

  4. HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。

  5. HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。

  6. Handler让具体的Controller执行。

  7. Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。

  8. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。

  9. DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。

    <!--视图解析器:DispatcherServlet给他的ModelAndView
    1. 获取了ModelAndView的数据
    2. 解析ModelAndView的视图名字
    3. 拼接视图名字,找到对应的视图/WEB-INF/jsp/hello.jsp
    4. 将数据渲染到这个视图上
    -->
    
  10. 视图解析器将解析的逻辑视图名传给DispatcherServlet。

  11. DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。

  12. 最终视图呈现给用户。

SpringMVC实现步骤

  1. 新建web项目
  2. 导入相关jar包
  3. 编写web.xml
  4. 编写springmvc配置文件
  5. 创建对应的控制类,controller
  6. 最后完善前段视图和controller之间的对应
  7. 测试运行调试

​ 使用springMVC必须配置三大件:

处理器映射器、处理器适配器、视图解析器

​ 通常,我们只需要手动配置视图解析器,而处理器映射器处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置

RestFul 风格

简洁、高效、安全。

//原来的: http://localhost:8080/add?a=1&b=2
@RequestMapping("/add")
public String test1(int a, int b, Model model){
    int res = a+b;
    model.addAttribute("msg","结果为"+res);
    return "test";
}

// RestFul:http://localhost:8080/add/a/b
// value="/add/{a}/{b}" == path="/add/{a}/{b}"
// 每个提交方式可以写成注解  
//@RequestMapping(value="/add/{a}/{b}",method = RequestMethod.GET) 等价于
 @GetMapping("/add/{a}/{b}")
@RequestMapping(value="/add/{a}/{b}",method = RequestMethod.DELETE)
public String test2(@PathVariable int a, @PathVariable int b, Model model){
    int res = a+b;
    model.addAttribute("msg","结果为"+res);
    return "test";
}

重定向和转发

不用视图解析器

转发 默认也是转发 可以不加forward:

@Controller
public class ControllerTest2 {

    @RequestMapping("/m1/t2")
    public String test1(Model model){
        model.addAttribute("msg","ModelTest1");
        return "forward:/WEB-INF/jsp/test.jsp";
    }
}

重定向

@Controller
public class ControllerTest2 {

    @RequestMapping("/m1/t2")
    public String test1(Model model){
        model.addAttribute("msg","ModelTest1");
        return "redirect:/WEB-INF/jsp/test.jsp";
    }
}

接收对象

//localhost:8080/user/t1?name=xxx;
// 加了@RequestParam之后  localhost:8080/user/t1?username=xxx;
@GetMapping("/t1")
public String test(@RequestParam("username") String name, Model model){
    //1. 接收前段参数

    //2.将返回的结果传递给前段,model
    model.addAttribute("msg",name);

    return "test";
}

/*
接收前端用户传递的参数,判断参数的名字,假设名字直接在方法上,可以直接使用
假设传递的是一个对象User,匹配User对象中的字段名:如果名字一致则OK,否则报错,为空

*/

Model ModelMap ModelAndview

Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;

ModelMap继承了Linkedrap ,除了实现了自身的一些方法,同样的继承 LinkedMap的方法和特性;

ModelAndview可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。

json

单个json解决乱码

@Controller
public class UserController {

    @RequestMapping(value = "/j1", produces = "application/json;charset=utf-8")
    @ResponseBody //它就不会走视图解析器,会直接返回一个字符串
    public String json1() throws JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();

        User user = new User("秦疆1号",3,"男");
        String str = mapper.writeValueAsString(user);

        return str;
    }

}

乱码统一解决 放得位置有问题也不能解决问题

<!--JSON乱码问题配置-->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <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>
//@Controller
@RestController  //直接返回字符串,不走视图解析 

@ResponseBody //它就不会走视图解析器,会直接返回一个字符串   用在方法上

在这里插入图片描述

在这里插入图片描述

需要阿里工具包

时间输出两种

@RequestMapping("/j2")
@ResponseBody //它就不会走视图解析器,会直接返回一个字符串
public String json2() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    Date date = new Date();

    //自定义日期格式
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年-MM月-dd日 HH:mm:ss");

    String s = mapper.writeValueAsString(sdf.format(date));


    return s;
}

@RequestMapping("/j3")
public String json3() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    //不适用时间戳的方式
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

    //自定义时间格式
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年-MM月-dd日 HH:mm:ss");
    mapper.setDateFormat(sdf);
    
    Date date = new Date();

    return mapper.writeValueAsString(date);

}

拦截器

  • 拦截器是AOP思想的应用

  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用

  • 拦截器只会拦截访问的控制器方法,如果访问的是jsp/html/css/image/js是不会进行拦截的

实现拦截器

想要自定义拦截器,必须实现HandlerInterceptor

public class MyInterceptor implements HandlerInterceptor {

    //return true;执行下一个拦截器, 也就是放行
    //return false;不执行下一个拦截器, 不放行
    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="com.can.config.MyInterceptor"/>
        </mvc:interceptor>
        
        <mvc:interceptor>
            <mvc:mapping path="/user/**"/>
            <bean class="com.can.config.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

文件上传

导包

<dependencies>
    <!--文件上传-->
    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.3</version>
    </dependency>
    <!--servlet-api导入高版本的-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
</dependencies>

表单要支持文件上传 要加上enctype=“multipart/form-data” ,要用post方式提交 get有大小限制

<form action="/upload" enctype="multipart/form-data" method="post">

springmvc-servlet.xml 添加配置

<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--请求的编码格式,必须和jsp的pageEncoding属性一致,以便于正确的
    读取表单的内容,默认ISO-8859-1
    -->
    <property name="defaultEncoding" value="utf-8"/>
    
    <!--
	下面两个可以不配置 有默认值
	上传文件大小上线,单位为字节10485760=10m-->
    <property name="maxUploadSize" value="10485760"/>
    <!--低于此值,只保留在内存里,超过此阈值,生成硬盘上的临时文件。-->
    <property name="maxInMemorySize" value="40960"/>
</bean>

文件上传方法

方式一

//@RequestParam("file")将name=file控件得到的文件封装成CommonsMultipartFiLe对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {

    //获取文件名:file.getOriginalFilename()
    String uploadFileName = file.getOriginalFilename();

    //如果文件名字为空,直接返回到首页
    if("".equals(uploadFileName)){
        return "rediret:/index.jsp";
    }
    System.out.println("上传文件名"+uploadFileName);

    //上传路径保存位置
    String path = request.getServletContext().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, uploadFileName));//文件输出流

    //读取写出
    int len=0;
    byte[] buffer = new byte[1024];
    
    while((len=is.read(buffer))!=-1){
        os.write(buffer,0,len);
        os.flush();
    }
    os.close();
    is.close();
    return "redirect:index.jsp";
}

方式二

/*
*  采用file.Transto来保存上传文件
*/
@RequestMapping("/upload")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {

    //上传路径保存位置
    String path = request.getServletContext().getRealPath("/upload");
    //如果路径不存在,创建一个
    File realPath = new File(path);
    if(!realPath.exists()){
        realPath.mkdir();
    }
    System.out.println("上传文件地址:"+realPath);

    //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
    file.transferTo(new File(realPath+"/"+file.getOriginalFilename()));
    
    return "redirect:index.jsp";
}

文件下载

方式一

在这里插入图片描述

方式二

@RequestMapping("/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
    //要下载的图片地址
    String path = request.getServletContext().getRealPath("/upload");
    String fileName ="基础语法.jpg";

    // 1、设置response啊应头
     response.reset(); //设置页面不缓存,清空buffer
     response.setCharacterEncoding( "UTF-8");//字符编码
     response.setContentType( "multipart/form-data");//二进制传输数据
    // 设置响应头
     response.setHeader("Content-Disposition",
                        "attachment;fileName="+ URLEncoder.encode(fileName,"UTF-8"));
    File file = new File(path,fileName) ;
    //2、读取文件--输入流
    InputStream input=new FileInputStream(file);
    //3、写出文件--输出流
    OutputStream out = response.getOutputStream();

    byte[] buff =new byte[1024];
    int index=0;
    //4、执行写出操作
    while( (index= input.read( buff))!= -1){
    out.write(buff,0, index) ;
    out.flush();
    }
    out.close();input.close();
    return null;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值