SpringMvc

SpringMvc

轻量级web框架,主要针对Contoller层

工作流程

  • 用户发送请求至前端控制器DispatcherServlet
  • DispatcherServlet收到请求调用HandlerMapping处理器映射器
  • 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  • DispatcherServlet调用HandlerAdapter处理器适配器
  • HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
  • Controller执行完成返回ModelAndView
  • HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  • DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  • ViewReslover解析后返回具体View
  • DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)
  • DispatcherServlet响应用户

1、搭建springMvc环境

1.1、配置文件

在web工程下配置DispatcherServlet的servlet

<!--注册DispatcherServlet,这是springmvc的核心,就是个servlet-->
    <servlet>
        <servlet-name>spring-mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--/ 匹配所有的请求;(不包括.jsp)-->
    <!--/* 匹配所有的请求;(包括.jsp)-->
    <servlet-mapping>
        <servlet-name>spring-mvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

在springMvc中,视图都放在WEB-INF中以保证视图安全。客户端必须通过访问servlet才能跳转到WEB-INF

<?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
    https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 处理映射器 -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!-- 处理器适配器 -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          id="internalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/page/" />
        <!-- 后缀 -->
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

编写一个Controller,继承Controller接口

public class FirstController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception {
        //ModelAndView 封装了模型和视图
        ModelAndView mv = new ModelAndView();
        //模型里封装数据
        mv.addObject("HelloMvc","Hello springMVC!");
        //封装跳转的视图
        mv.setViewName("HelloMvc");
        //不是有个视图解析器吗
        //这玩意就是为了省事的,自动给你加个前缀后缀
        //就成了 /jsp/hellomvc.jsp 不就是拼串吗
        return mv;
    }
}

spingMvc默认去找WEB-INF下的spring-mvc-servlet.xml ,要创建一个spring-mvc-servlet.xml 文件

<bean id="/hellomvc" class="com.xinzhi.controller.FirstController"/>

1.2、注解

注解就要扫包

<!-- 自动扫包 -->
<context:component-scan base-package="com.xinzhi"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 让springmvc自带的注解生效 -->
<mvc:annotation-driven />
@Controller//说明是Controller层
@RequestMapping("/user/") //路径
  public class UserController {
  //一个主路径可以有多个子路径,多个功能可以由一个servlet来处理
  @RequestMapping("login")
  public String login(Model model) {
    model.addAttribute("ogin","denlu!");
    return "Login";
  } 
  @RequestMapping("register")
  public String register(Model model) {
    model.addAttribute("egister","zhuce!");
    return "Register";
	}
}

2、深入学习

2.1、视图模型分离

之前返回的是模型加视图,耦合性太高,有时候不需要跳转视图也会强行跳转
使用Model参数

@RequestMapping(value = "login")
public String login(Model model) {
    model.addAttribute("ogin","登录!");
    return "Login";
}

2.2、@RequestMapping

这个注解很强大,可以放在方法上也可以放在类上,放在类上所有方法都默认加上
该注解有六个参数

  • value:访问路径
  • method :指定请求类型,如post、get等
  • consumes :指定处理请求后提交的数据类型(Content-Type),如json,text
  • produces :指定返回值类型
  • params :指定request中必须有哪些参数,有才能让此方法执行
  • headers :指定request中必须包含某些指定的header值 ,有才能让此方法执行

2.3、字符集处理

<!--在web.xml里配置-->
<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>

2.4、传参

不需要在一个个的getParameter(),要什么直接拿

@RequestMapping(value = "login",method = RequestMethod.POST)
public String login(Model model, User user) {
  System.out.println(user.getUsername());
  System.out.println(user.getId());
  System.out.println(user.getPassword());l
  model.addAttribute("login","登录!");
  return "Login";
}

2.5、返回json数据

手动转换
<!--依赖-->
  <dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.68</version>
</dependency> 
//方法上设置
@RequestMapping(value = "get",produces = "text/json;charset=utf-8")
自动转换
<mvc:annotation-driven >
  <mvc:message-converters>
    <bean id="fastjson"
          class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
      <property name="supportedMediaTypes">
        <list>
          <value>text/html;charset=UTF-8</value>
          <value>application/json;charset=UTF-8</value>
        </list>
      </property>
    </bean>
  </mvc:message-converters>
</mvc:annotation-driven>
@RequestMapping("set")
//直接将返回值以数据的形式返回到响应体
@ResponseBody
public User set(@Validated User user, BindingResult br) {
  List<ObjectError> allErrors = br.getAllErrors();
  for (ObjectError allError : allErrors) {
    System.out.println(allError.getCode()+"---"+allError.getDefaultMessage());
  }
  System.out.println(user.getId());
  return user;
}

2.6、数据转化

@DateTimeFormat(pattern = "yyyy-mm-dd")
private Date birthday;
@NumberFormat(pattern = "#,###,###.#")
private Double salary;

2.7、数据校验

@Max(value = 20L,message = "id不能大于20")
private int id;
@NotNull(message = "名字不能为空")
private String username;
@Null
private String password;

@RequestMapping("set")
@ResponseBody
//用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。
public User set(@Validated User user, BindingResult br) {
  //拿到错误,不会挡住请求
  List<ObjectError> allErrors = br.getAllErrors();
  for (ObjectError allError : allErrors) {
    System.out.println(allError.getCode()+"---"+allError.getDefaultMessage());
  }
  System.out.println(user.getId());
  return user;
}

2.8、重定向和请求转发

直接返回字符串就是请求转发

return "index"

返回时添加redirect就是重定向

return "redirect:http://www.baidu.com"
return "redirect:/index.jsp"

重定向可以传参

@RequestMapping("reg")
public String reg(RedirectAttributes attributes) {
  attributes.addAttribute("name","lin");
  return "redirect:/index.jsp"
}

3、restful

请求url请求方式操作
/user/1get获取一个id为1的user
/user/1delete删除id为1的对象
/user/1put更新id为1的对象
/user/addpost新增一个对象
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@RequestMapping(value = "/add", method = RequestMethod.POST)
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
//或
@GetMapping("/user/{id}")
@PostMapping("/user/add")
@DeleteMapping("/user/{id}")
@PutMapping("/user/{id}")
//根据id获取一个对象
@GetMapping("/rest/{id}")
@ResponseBody
public User getUser(@PathVariable int id) {
  return new User();
}

//根据id获取一个对象
@DeleteMapping("/rest/{id}")
@ResponseBody
public R deleteUser(@PathVariable int id) {
  System.out.println(id);
  return R.success();
}

//根据id获取一个对象
@PutMapping("/rest/{id}")
@ResponseBody
public R updateUser(@PathVariable int id, User user) {
  System.out.println(id);
  System.out.println(user);
  return R.fail();
}

//添加一个对象
@PostMapping("/rest/add")
@ResponseBody
public R addUser(User user) {
  System.out.println(user);
  return R.build(304, "插入发生异常")
    .put("reason ", "超时了!")
    .put("other", "暗藏");
}

ajax

$.ajax( {
  type : "GET",
  url : "http://localhost:8080/springmvc/user/rest/1",
  dataType : "json",
  success : function(data) {
    console.log("get请求!---------------------")
    console.log(data)
    }
});  

4、拦截器

  • SpringMVC提供的拦截器类似于JavaWeb中的过滤器,只不过SpringMVC拦截器只拦截被前端控制器拦截的请求,而过滤器拦截从前端发送的任意请求。
  • 熟练掌握 SpringMVC 拦截器对于我们开发非常有帮助,在没使用权限框架( shiro,spring security )之前,一般使用拦截器进行认证和授权操作。
  • SpringMVC拦截器有许多应用场景,比如:登录认证拦截器,字符过滤拦截器,日志操作拦截器等等。

4.1、自定义拦截器

自定义的 Interceptor类要实现了pring的HandlerInterceptor接口

public class LoginInterceptor implements HandlerInterceptor {
  //拦截前
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) {
    //放行
    return true;
  } 
  
	//拦截后
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    
  }

  //所有拦截完成后
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    
  }
}

4.2、拦截流程

客户端发出请求,经过preHandle,通过后入controller,controller处理完进入postHandle通过view、afterCompletion响应到用户

4.3、拦截规则

我们可以配置多个拦截器,每个拦截器中都有三个方法。下面将总结多个拦截器中的方法执行规律。

  • preHandle:Controller方法处理请求前执行,根据拦截器定义的顺序,正向执行。
  • postHandle:Controller方法处理请求后执行,根据拦截器定义的顺序,逆向执行。需要所有的preHandle方
    都返回true时才会调用。
  • afterCompletion:View视图渲染后处理方法:根据拦截器定义的顺序,逆向执行。preHandle返回true就会
    调用

4.4、登录拦截器

public class LoginInterceptor implements HandlerInterceptor {
/**
在执行Controller方法前拦截,判断用户是否已经登录,
登录了就放行,还没登录就重定向到登录页面
*/
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
  Object handler) {
    HttpSession session = request.getSession();
    User user = session.getAttribute("user");
    if (user == null){
      //还没登录,重定向到登录页面
      response.sendRedirect("/user/toLogin");
    }else {
    //已经登录,放行
    return true;
    }
  }
  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response,
  Object handler, ModelAndView modelAndView) {}
  
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse
  response, Object handler, Exception ex) {}
}

编写完SpringMVC拦截器,我们还需要在springmvc.xml配置文件中,配置我们编写的拦截器,配置代码如下:

  • 配置需要拦截的路径
  • 配置不需要拦截的路径
  • 配置我们自定义的拦截器类
<!--配置拦截器-->
<mvc:interceptors>
  <mvc:interceptor>
    <!--
      mvc:mapping:拦截的路径
      /**:是指所有文件夹及其子孙文件夹
      /*:是指所有文件夹,但不包含子孙文件夹
      /:Web项目的根目录
     -->
    <mvc:mapping path="/**"/>
    <!--mvc:exclude-mapping:不拦截的路径-->
    <mvc:exclude-mapping path="/user/toLogin"/>
    <mvc:exclude-mapping path="/user/login"/>
    <!--class属性就是我们自定义的拦截器-->
    <bean id="loginInterceptor"class="cn.zwq.springmvc.interceptor.LoginInterceptor"/>
  </mvc:interceptor>
</mvc:interceptors>

5、文件上传

maven依赖

<!--文件上传-->
  <dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.3</version>
</dependency>

配置bean

<!--文件上传配置-->
<!--这个bena的id必须为:multipartResolver-->
<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>

前端页面

<form action="/upload" enctype="multipart/form-data" method="post">
  <input type="file" name="file"/>
  <input type="submit" value="upload">
</form>

controller

@PostMapping("/upload")
@ResponseBody
public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws Exception{
  //获取文件名 : file.getOriginalFilename();
  String uploadFileName = file.getOriginalFilename();
  System.out.println("上传文件名 : "+uploadFileName);
  //上传路径保存设置
  String path = "D:/upload";
  //如果路径不存在,创建一个
  File realPath = new File(path);
  if (!realPath.exists()){
 		 realPath.mkdir();
  } 
  System.out.println("上传文件保存地址:"+realPath);
  
  file.transferTo(new File(path+"/"+uploadFileName));
  return "yes";
}

6、文件下载

ResponseEntity

@GetMapping("/download")
@ResponseBody
public ResponseEntity<byte[]> download2(){
try {
      String fileName = "czx.jpg";
      byte[] bytes = FileUtils.readFileToByteArray(new File("D:/upload/"+fileName));
      HttpHeaders headers=new HttpHeaders();
      headers.set("Content-Disposition","attachment;filename="+
      URLEncoder.encode(fileName, "UTF-8"));
      headers.set("charsetEncoding","utf-8");
      headers.set("content-type","multipart/form-data");
  
      ResponseEntity<byte[]> entity=new ResponseEntity<byte[]>(bytes,headers,HttpStatus.OK);
      return entity;
} catch (IOException e) {
  e.printStackTrace();
  return null;
}
}

7、全局捕获异常

@Component
public class MyExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        e.printStackTrace();
        //把日志存起来
        ModelAndView mv = new ModelAndView();
        mv.setViewName("error");
        return mv;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值