框架之初识SpringMVC

一、SpringMVC简介

SpringMVC是一个工作在web层的框架,底层封装了Servlet。

SpringMVC通过对Servlet的封装,解决了Servlet繁琐代码的书写问题。
在这里插入图片描述

二、SpringMVC内部实现

SpringMVC可以将Servlet一些通用功能进行了抽取和封装,使用它之后,web部分就有两部分组成:

  • 前端控制器:由SpringMVC提供,主要负责接收参数和返回页面和数据
  • 处理器: 开发人员实现,主要负责参数的处理和业务层调用

在这里插入图片描述

2.1 框架内部流程

在这里插入图片描述

2.2 SpringMVC三大组件

  • 处理器映射器:HandlerMapping,负责根据URL寻找对应的处理器方法
  • 处理器适配器:HandlerAdapter,负责真正的去调用某个处理器方法
  • 视图解析器:ViewResolver,负责将逻辑视图转换成物理视图

在这里插入图片描述
自定义视图解析器时,会覆盖默认的视图解析器:
在这里插入图片描述

2.3 常用注解

  1. @Controller
@Controller  //交给Spring容器
public class UserController {

}
  1. @RequestMapping

作用:建立url和方法映射,用于处理前端请求
位置:

  • 类上:一级路径
  • 方法上:二级路径 / 方法上:一级路径/二级路径

常用属性:

属性说明
value/path指定当前方法的url地址,一个方法可以绑定多个地址
params限定前端请求,必须携带指定参数
method限定请求方式:get、post、put、delete等等\
@RequestMapping(path = {"/hello","/haha"},params = {"username","password"},method = {RequestMethod.POST,RequestMethod.GET})
public String hello() {
    System.out.println("hello方法执行了...");
    return "success";
}

三、SpringMVC请求详解

3.1 请求参数类型

  1. 简单类型
    基本类型\基本类型的包装类型\字符串
<form action="/simpleParam" method="post">
    姓名:<input type="text" name="username"> <br>
    年龄:<input type="text" name="age"> <br>
    <input type="submit" value="简单类型提交">
</form>
@RequestMapping("/simpleParam")
public String simpleParam(String username,Integer age){ // request.getParameter("username")
    System.out.println(username);
    System.out.println(age);
    return "success";
}
  1. 对象类型
    在这里插入图片描述
@RequestMapping("/pojoParam")
public String pojoParam(User user){ // request.getParameterMap() 
    System.out.println(user);
    return "success";
}
  1. 数组类型
<form action="/arrayParam" method="post">
    抽烟:<input type="checkbox" name="hobbies" value="1"> <br>
    喝酒:<input type="checkbox" name="hobbies" value="2"> <br>
    烫头:<input type="checkbox" name="hobbies" value="3"> <br>
    <input type="submit" value="数组类型提交">
</form>
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobbies){ // request.getParameterValues("hobbies")
    System.out.println(Arrays.toString(hobbies));
    return "success";
}
  1. 集合类型
    注意:如果后端使用list集合接收前端请求参数,必须配合一个注解@RquestParam使用
<form action="/listParam" method="post">
    陪吃:<input type="checkbox" name="hobbies" value="1"> <br>
    陪喝:<input type="checkbox" name="hobbies" value="2"> <br>
    配shui:<input type="checkbox" name="hobbies" value="3"> <br>
    <input type="submit" value="集合类型提交">
</form>
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobbies){
    System.out.println(hobbies);
    return "success";
}

3.2 请求过程中常出现的问题

3.2.1 中文乱码

中文乱码常出现在前端post方式提交中,原因:

  • 前端get方式提交:默认浏览器和服务器编码解码都是utf-8
  • 前端post方式提交:浏览器根据utf-8编码,servlet根据默认规范iso-8859-1解码,由于编码和解码码表不一致,所以出现乱码

解决方法:

<!--乱码过滤器-->
<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>

3.2.2 日期类型报错

springMVC框架时默认接收的格式为yyyy/MM/dd,但是如果使用格式为:yyyy-MM-dd,由于提交格式不同,就会导致框架接收日期类型失败报错。

<form action="/dateParam" method="post">
    生日:<input type="text" name="birthday"> 【格式:1999-01-15<br>
    <input type="submit" value="日期类型">
</form>
  1. 通过注解方式解决
@RequestMapping("/dateParam")
public String dateParam (@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday){
	System.out.println(birthday);
	return "success";
}
  1. 通过自定义转换器解决
public class DateConverter implements Converter<String, Date> {

    @Override
    public Date convert(String source) { // 前端提交的字符串(1999-12-15)
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            return sdf.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException("日期格式非法...");
        }
    }
}
<!--开启mvc注解支持-->
<mvc:annotation-driven conversion-service="conversionService">

<!--添加自定义转换器-->
 <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
 	<property name="converters">
 		<set>
 			<bean class="com.baidu.web.converter.DataConverter"></bean>
 		</set>
	</property>
</bean

3.3 请求过程中常用注解

  1. @RequestParam
    用于接收前端请求参数,通常使用在方法的形参上
属性说明
required默认值true,要求前端必须提供参数,否则报错
defaultValue给参数提供默认值
name接收指定前端的参数名
<a href="/findByPage?pageNo=2&ps=8">分页查询</a>
@RequestMapping("/findByPage")
public String findByPage(
	@RequestParam(name = "pageNo",defaultValue = "1") Integer pageNum, 
	@RequestParam(name = "ps",defaultValue = "10") Integer pageSize) 
{
    System.out.println("当前页:" + pageNum);
    System.out.println("每页个数:" + pageSize);
    return "success";
}
  1. @RequestHeader
    相当于:request.getHeader(“请求头的名称”);
<a href="/requestHeader">请求头</a>
@RequestMapping("/requestHeader")
public String requestHeader(@RequestHeader("User-Agent") String userAgent) {
    System.out.println("浏览器信息:" + userAgent);
    return "success";
}

3.4 获取Servlet相关API

<a href="/servletApi?useranme=haha&age=18">原生的servletAPI</a>
@RequestMapping("/servletApi")
public void servletApi(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws ServletException, IOException {
    String useranme = request.getParameter("useranme");
    System.out.println(useranme);
    String ageStr = request.getParameter("age");
    Integer age = Integer.parseInt(ageStr);
    System.out.println(age);

    request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
}

四、使用SpringMVC实现文件上传

4.1 文件上传流程

在这里插入图片描述

4.2 SpringMVC实现

  1. 导入坐标
<!--文件上传工具包-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
  1. 配置spring-mvc.xml
 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--
            限制文件大小,单位B
                1KB = 1024B
                1MB = 1024KB
        -->
        <property name="maxUploadSize" value="1000000"></property>
    </bean>

文件上传解析器 id=“multipartResolver” 这个值是固定的

  1. index.jsp
<form action="/fileUpload" method="post" enctype="multipart/form-data">
    姓名:<input type="text" name="username"> <br>
    头像:<input type="file" name="picFile"> <br>
    <input type="submit" value="提交">
</form>
  1. UserController
@RequestMapping("/fileUpload")
public String fileUpload(String username, MultipartFile picFile) throws IOException {
    System.out.println(username);

    System.out.println(picFile.getOriginalFilename()); // 原始文件名
    picFile.transferTo(new File("E:\\"+picFile.getOriginalFilename())); // 文件io复制,报错文件
    return "success";
}

五、开启静态资源的访问

在SpringMVC的前端控制器DispatcherServleturl-pattern配置的是 /(缺省【默认】),代表除了jsp请求不拦截, 其他的所有请求都会拦截,包括一些静态文件(html、css、js、img)等, 而拦截住之后,它又找不到对应的处理器方法来处理, 因此报错.
在这里插入图片描述
在这里插入图片描述

  1. 手动映射
    在这里插入图片描述
  2. 自动映射
    在这里插入图片描述
    在这里插入图片描述

六、ajax异步交互

在SpringMVC中,ajax异步交互主要是通过两个注解@RequestBody和@ResponseBody实现的。
在这里插入图片描述

  • @RequestBody 用于接收前端传递的请求体中的json数据, 并可以自动转换封装进指定的对象中
  • ResponseBody 用于将controller方法返回的对象通过转换器转换为指定的格式(通常为json)之后,写入到response对象的响应体中

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>index</title>
    <script src="/js/axios-0.20.0.js"></script>
</head>
<body>
<h3>springMVC知识学习</h3>

<button id="btn">发送异步请求</button>

<div id="myDiv"></div>

<script>
    document.getElementById('btn').onclick = function () {
        // 发送ajax异步请求
        let data = {id: 1, username: 'jack', age: 18, address: '北京顺义'};
        axios.post('/ajaxApi', data).then(resp => {
            document.getElementById('myDiv').innerHTML = resp.data.username;
        })
    }
</script>
</body>
</html>

User

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private Integer id;
    private String username;
    private Integer age;
    private String address;
}

UserController

@RequestMapping("/ajaxApi")
@ResponseBody // 将user转为json,设置到响应体返回到浏览器
public User ajaxApi(@RequestBody User user) { // 将前端请求体的json转为java对象【底层使用了jackson】
    System.out.println(user);
    user.setUsername("lucy");
    return user; 
}

七、异常处理

java对于异常的处理一般有两种方式:

  • 一种是当前方法处理(try-catch),这种处理方式会造成业务代码和异常处理代码的耦合。
  • 一种是当前方法不处理, 出现异常后直接抛给调用者处理。

​ 使用Spring框架后,代码最终是由框架来调用的。也就是说,异常最终会抛到框架中, 然后由框架指定异常处理器来统一处理异常。
在这里插入图片描述

7.1 自定义异常处理器

创建一个普通类,实现HandlerExceptionResolver接口

@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {

    /*
        捕获并处理异常信息
            请求:
                request
                response
                handler: 用户具体调用处理的某个方法
                ex:具体的异常信息
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView();
        // 将错误信息,写入到日志中
        modelAndView.addObject("error", "sorry,服务器繁忙,请稍后重试~~~");
        modelAndView.setViewName("forward:/WEB-INF/error.jsp");
        return modelAndView;
    }
}

7.2 @ControllerAdvice

@ControllerAdvice配合@ExceptionHandler注解结合使用,当异常抛到controller层时,可以对异常进行统一的处理

@ControllerAdvice
public class MyControllerAdvice {


    @ExceptionHandler(Exception.class)
    public String ExceptionHandler(Exception ex,Model model){
        ex.printStackTrace();
        model.addAttribute("error", "服务器繁忙...");
        return "forward:/WEB-INF/error.jsp";
    }



    @ExceptionHandler(NullPointerException.class) // 专门捕获空指针异常
    public String NullExHandler(NullPointerException npe, Model model) {
        npe.printStackTrace();
        model.addAttribute("error", "这是一个空指针异常");
        return "forward:/WEB-INF/error.jsp";
    }

    @ExceptionHandler(ArithmeticException.class) // 专门捕获数学异常
    public String ArithmeticExceptionHandler(ArithmeticException ae,Model model){
        ae.printStackTrace();
        model.addAttribute("error", "这是一个数学异常");
        return "forward:/WEB-INF/error.jsp";
    }
}

7.3 配置web.xml

<!--捕获并处理异常-->
<error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/404.jsp</location>
</error-page>

八、拦截器

Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理后处理
在这里插入图片描述

  • Filter: web提供的过滤器技术,可以拦截一切资源(jsp、servlet、SpringMVC),不可以获取Spring容器中的对象
  • intercepter: SpringMVC提供的拦截器技术,只能拦截前端控制器内的资源,可以获取Spring容器中的对象

编写拦截器:

public class MyIntercepter1 implements HandlerInterceptor {


    /*
        预处理方法:拦截请求
        参数:
            request
            response
            handler:用户访问的目标方法
        返回结果:
            true:放行
            false:拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("preHandle1");
        return true;
    }
 /*
        视图渲染完处理的:资源释放
            参数:
                request
                response
                handler
                ex:异常
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("afterCompletion1");
    }
}

配置拦截规则(地址)

<!--拦截器配置-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/target"/>
        <bean class="com.baidu.web.intercepter.MyIntercepter1"></bean>
    </mvc:interceptor>
</mvc:interceptors>

拦截过程
在这里插入图片描述
开发中拦截器可以单独使用,也可以同时使用多个拦截器形成一条拦截器链。

开发步骤和单个拦截器是一样的,只不过注册的时候注册多个,注意这里注册的顺序就代表拦截器执行的顺序。

拦截器的执行顺序是先进后出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值