SpringMVC学习

SpringMVC:
1.jar
spring-aop.jar
spring-bean.jar
spring-context.jar
spring-core.jar
spring-web.jar
spring-webmvc.jar

如果报错NoClassDefFoundError,说明项目缺少jar包NoClassDefFoundError,说明项目缺少jar包

2.第一个SpringMVC程序
Servlet -> SpringMVC
jsp -> Servlet(SpringMVC) ->jsp

SpringMVC配置文件springmvc.xml
选中常用的命名空间:beans aop context mvc

普通的servlet的流程:
请求- url-patten - 交给对应的servlet,如何告知程序?-如何让springmvc介入程序:
需要配置一个springmvc自带的servlet

通过以下配置,拦截所有请求,交给SpringMVC处理:
  <servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>springDispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

其中:
 <url-pattern>/</url-pattern>
 /:一切请求,注意请求不是/*
 /user:拦截以 /user开头的请求
 /user/abc.do :只拦截该请求
 .action:只拦截.action结尾的请求

项目中同时兼容 springMVC和Servlet
<servlet-mapping>
    <servlet-name>springDispatcherServlet</servlet-name>
    <url-pattern>.action</url-pattern>
  </servlet-mapping>

  <servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 初始化参数,告诉MVC的配置参数在哪里 -->
    <!--如果MVC的配置地址与该web.xml在同一目录下,可以省去此配置,但是MVC的配置文件名必须为springDispatcherServlet-servlet.xml-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springMVC.xml</param-value>
    </init-param>
    通过该配置指定springmvc配置文件的路径,如果要省略,必须放到默认路径:
    /WEB-INF/springDispatcherServlet-servlet.xml

    <!-- 初始化参数, 项目启动时,以第一的身份自动加载,配置自动生效-->
    <load-on-startup>1</load-on-startup>
  </servlet>

映射是去匹配@RequestMapping()注解
通过method指定 请求方式(get post delete put)
  @RequestMapping(value="welcome",method=RequestMethod.POST)//映射

设置name="xxxx"的情况
params= {"name2=zs","age!=23"}
name2:必须有name="name2"参数
age!=23: a.如果有name="zs",则age值不能是23】
         b.没有age
!name2:    参数中不能含有name=!name2


ant风格的请求路径:
?   单字符
*   任意个字符(0或)
**  任意目录

例子:
@RequestMapping(value="welcome/**/test")
接受实例: <a href="welcome/aba/syz/123/test"></a>


@PathVariable获取动态参数

REST风格:软件编程风格
Springmvc:
GET: 查
POST: 增
DELETE: 删
PUT: 改

普通浏览器只支持GET和POST方式,其他请求方式如delete和put请求是通过过滤器新加入的支持

过滤的条件:
1.<input  type="hidden" name="_method" value="delete/put">

2.请求方式为post


Springmvc实现:put/post请求方式的步骤
a.增加过滤器
  <!-- 增加HiddenHttpMethodFilter过滤器:目的是给普通浏览器增加put/delete请求方式 -->
  <filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

b.表单
  <form action="SpringMVCHandler/testDelete/1234" method="post">
     <input type="hidden" name="_method" value="DELETE"/>
     <input  type="submit" value="删">
  </form>
  i:必须是post方式
  ii:通过隐藏域的value值设置实际的请求方式DELETE|PUT

c.控制器
   @RequestMapping(value="testDelete/{id}",method=RequestMethod.DELETE)//映射
    public String testDelete(@PathVariable("id")Integer id) {
        System.out.println("delete:删"+id);
        return "success";//  /view/success.jsp 默认使用了请求中转发的跳转方式
        //success:会增加解析器中prefix,suffix
    }

通过 ,    method=RequestMethod.DELETE  匹配具体的请求方式

此外,可以发现,当映射相同时@RequestMapping(value="testRest"),可以通过method处理不同的请求

过滤器中 处理put|delete请求的部分源码:
@Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        HttpServletRequest requestToUse = request;

        if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
            String paramValue = request.getParameter(this.methodParam);
            if (StringUtils.hasLength(paramValue)) {
                requestToUse = new HttpMethodRequestWrapper(request, paramValue);
            }
        }

        filterChain.doFilter(requestToUse, response);
    }

原始请求:request,该请求默认只支持get post  header
但是如果是"POST" 并且有隐藏域  <input type="hidden" name="_method" value="DELETE"/>
则,过滤器将原始的请求request加入新的请求方式DELETE,并将原始请求转为requestToUser 请求(request+delete请求)
最后将requestToUser 放入请求链中,后续再事情request时 实际就使用改造后的requestToUser


@RequestParam("uname") String name,@RequestParam(value="uage",required=false,defaultValue="23")

@RequestParam("uname"):接受前台传递的值,等价于request.getParameter("uname");

required =false:该属性 不是必须的。
defaultValue = "23":默认值23

获取请求头信息 @RequestHeader
public String testPut(@RequestHeader("Accept-Language")String al){}
通过@RequestHeader("Accept-Language") String al 获取请求头中的Accept-Language值,并将值保存在al变量中


通过mvc获取cookie值(JSESSIONID)
@CookieValue
(前置知识:服务器在接受客户端第一次请求时,会给该客户端分配一个session(该session包含一个sessionId)), 并且服务器端会在第一次响应客户端时,
将该sessionId赋值给JSESSIONID并传递给客户端cookie中


小结:
SpringMVC处理各种参数的流程/逻辑:
请求:前段发送请求a->@RequestMapping("a")
处理请求中的参数xyz
  @RequestMapping("a")
  public String aa(@Xxx注解("xyz") xyz){

  }


使用对象(实体类Student)接受请求参数

在SpringMVC中使用原生态的Servlet API :HttpServletRequest:直接将 servlet-api中的类、接口等写在springMVC所映射的方法参数中即可。


处理模型数据
如果跳转时需要带数据:V,M则可以使用以下方式
ModelAndView、ModelMap、Map、Model 数据放在了request作用域

@SessionAttributes、@ModelAttribute

示例:
public String testModel(Model model |  Map<String,Object> m | ModelMap mm) {

     m.put(x,"..");就会将x对象放入request域中
    }


如何将上述数据放入session中?加上@SessionAttributes()

@ModelAttribute
  i.经常在更新时候使用
  ii.在不改变原有代码的基础上插入一个新的方法


通过@ModelAttribute修饰的方法,会在每次请求前先执行,
并且该方法的参数map.put()可以将对象放入即将查询的参数中。
必须满足的约定:
map.put(k.v); 其中的k必须是即将查询的方法参数的首字母小写
testModelAttribute(Student xxx),即student;
如果不一致,需要通过@ModelAttribute声明。如下
@ModelAttribute//在任何一次请求钱,都会先执行@ModelAtttibute修饰的方法
    public void queryStudentById(Map<String ,Object> map) {
        //模拟调用三层查询数据库的操作
        Student student = new Student();
        student.setId(31);
        student.setName("zs");
        student.setAge(21);
        //map.put("student",student);//约定:map的key就是方法参数类型的首字母小写
        map.put("stu",student);
    }
    //修改
    @RequestMapping(value="testModelAttribute")
    public String testModelAttribute(@ModelAttribute("stu")Student student) {
        student.setName(student.getName());//将名字zs改为ls
        System.out.println(student.getId()+","+student.getName()+","+student.getAge());
        return "success2";
    }

一个servlet对应一个功能;
增删改查 对应于 4个Servlet

查: Servlet - SpringMVC的Controller

@ModelAttribute
public void query(){

}
修改
public String update(){

}

@ModelAttribute 会在该类的每个方法执行前均被执行一次,因此使用时需要注意


2.视图、视图解析器

Controller返回值

String(sussess)
View(success)         ===》  ModelAndView  ==》 视图解析器    ==> 视图
ModelAndView                                   ViewResolver        View (渲染)(Jsp/PDF/Excel)

视图的顶级接口:View
视图解析器的顶级接口:ViewResolver

常见的视图和解析器:
InternalResourceView、InternalResourceViewResolver

public class JstlView extends InternalResourceView:
springMVC解析jsp时,会默认使用InternalResourceView,如果发现jsp中包含jstl语言,则自动转为JstlView

JstlView可以解析jstl\实现国际化操作

国际化:针对不同地区、不同国家,进行不同的显示

具体实现国际化步骤:
a.创建资源文件
  基名_语言_地区.properties 
  基名_语言.properties 
  
b.配置springmvc.xml 加载资源文件
    <!-- 加载国际化资源文件
      1.将ResourceBundleMessageSource在程序加载时,加入springmvc:pringmvc在启动时,会自动查找一个id="messageSource"的bean,如果有则自动加载
      2.配置了ResourceBundleMessageSource,则该类会在程序相应的时介入
    -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
      <property name="basename" value="i18n"></property>
    </bean>
    
ResourceBundleMessageSource会在springmvc响应程序时介入(解析国际化资源文件)    
        
c.通过jstl使用国家化 
jstl.jar standard.jar

springmvc在启动时,会自动查找一个id="messageSource"的bean,如果有则自动加载


i18n_zh_CH.properties
resource.welcome=你好
resource.exist=退出

i18n.properties

1.<mvc:view-controller..>
InternalResourceViewResolver
index.jsp  ->  Controller(@RequestMapping) -> succes.jsp

要用SpringMVC实现:index.jsp -> succes.jsp
<mvc:view-controller path="SpringMVCHandler/welcome" view-name="success">

以上注解,会让所有的请求 转入<mvc..>中匹配映射地址,而被忽略掉@RequestMapping();
如果想让@RequestMapping("a")和<mvc:...>共存,则需要加入一个注解:<mvc:annotation-driven></mvc:annotation-driven>


2.指定请求方式
指定跳转方式:return "forward:/views/success.jsp";
forward:  、  redirect:   ,需要注意此种方式,不会被视图解析器加上前缀(/views)、后缀(.jsp)

forward:请求转发     redirect:重定向

2.处理静态资源:html css js 图片 视频
可以与用户交互,因为时间/地点的不同而结果不同的内容:动态(百度:天气)
 
在springMVC中,如果直接访问静态资源:404 原因:之前将所有的请求通过通配符"、"拦截,进而小哥女Springmvc的入口DispatcherServlet去处理:找该请求映射对应的@RequesMapping

http://localhost:8080/SpringMVCProject/img.png 

@RequestMapping("img.png")

解决:如果是需要mvc处理的,则交给@RequesMapping("img.png")处理,如果不需要springmvc处理,则使用
tomcat默认的Servlet去处理:如果有对应的请求拦截,则交给相应的servlet去处理,如果没有相应的servlet,则直接访问。
tocmcat默认的Servlet在哪里?在tomcat配置文件\conf\web.xml中

  <servlet>
    <servlet-name>abc</servlet-name>
    <servlet-class>xxx.xxx.xx.ABCServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>abc</servlet-name>
    <url-pattern>/abc</url-pattern>
  </servlet-mapping>

解决静态资源方案:如果有springmvc对应的@requestMapping则交给spring处理,如果没有对应的@requestMapping,则交给服务器Tomcat默认的servlet去处理:实现方法,只需要增加两个注解即可 springmvc.xml:
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:annotation-driven></mvc:annotation-driven>

总结:要让springmvc访问静态资源,只需要加入以下2个注解:
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:annotation-driven></mvc:annotation-driven>

4.类型转换
a.Spring自带一些常见的类型转换器:
public String testDelete(@PathVariable("id") String id) . 既可以接受int类型数据id,也可以接受String类型数据

a.可以自定义类型转换器
i.编写自定义类型转换器的类(实现Converter接口)
public class MyConverter implements Converter<String,Student>{

    @Override
    public Student convert(String source) {//source:2-zs-23
        //cource接收前端传来的String:2-zs-23
        String[] studentStrArr = source.split("-");
        Student student = new Student();
        student.setId(Integer.parseInt(studentStrArr[0]));
        student.setName(studentStrArr[1]);
        student.setAge(Integer.parseInt(studentStrArr[2]));
        return student;
    }
    
2.配置:将MyConverter加入到springmvc中    

  <!-- 1将自定义转换器纳入SpringIOC容器 -->
  <bean id="myConverter" class="org.lanqiao.converter.MyConverter"></bean>
  
  <!-- 2将myConverter再纳入SpringMVC提过的转换器bean -->
  <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
       <set>
         <ref bean="myConverter"/>
       </set>
    </property>
  </bean>
  
  <!-- 3将 conversionService注册到annotation-driven中-->
  <!-- 此配置是SpringMVC的基础配置,很多功能都需要通过该注解来协调 -->
  <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

5.数据格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
SpringMVC提供了很多的注解 ,方便我们数据格式化
实现步骤:
a.配置
   <!-- 配置数据格式化 注解 所依赖的bean -->
  <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
  
b.通过注解使用

@DateTimeFormat(pattern="yyyy-MM-dd")
@NumberFormat(pattern="###,#")

错误消息:
public String testDateTimeFormat(Student student,BindingResult result,Map<String,Object> map){
需要验证的数据是Student中的birthday,SpringMVC要求如果校验失败则将错误信息自动放入该对象之后紧挨的BindingResult中。
即Student student,BindingResult result之间不能有其他参数。

如果要讲控制台的错误信息传到jsp中显示,则可以将错误信息对象放入request域中,然后在jsp中从request中获取。

2.数据校验
JSR303

Hibernate Validator

使用Hibernate Validator步骤:
a.jar
hibernate-validator.jar --注意版本问题(可能出现不兼容)
classmate.jar
jboss-logging.jar
validatetion-api.jar
hibernate-validator-annotation-processor.jar 

b.配置
 <mvc:annotation-driven></mvc:annotation-driven>
 此时mvc:annotation-driven的作用,要实现Hibernate Validator/JSR303 校验(或者其他各种校验),必须实现SpringMVC提供的一个接口:ValidatorFactory
 
 LocalValidatorFactoryBean是ValidatorFactory的一个实现类
 <mvc:annotation-driven></mvc:annotation-driven>会在springmvc容器中自动加载一个LocalValidatorFactoryBean类,因此可以直接实现数据校验
 
c.直接使用注解
public class Student{
  @Past//当前时间以前
  private Date birthday;
  
}

在校验的Controller中,给校验的对象前增加@Valid
    public String testDateTimeFormat(@Valid Student student,BindingResult,Map<String,Object> map){...}


3.Ajax请求SpringMVC,并且JSON格式的数据
a.jar
jackson-annotations.jar
jackson-core.jar
jackson-databind.jar

b.
@ResponseBody修饰的方法,会将该方法的返回值以一个json数组的形式返回给前台


============================================================

SpringMVC实现文件上传:
和Servlet方式的本质一样,都是通过commons-fileupload.jar和commons-io.jar
SpingMVC可以简化文件上传的代码,但是必须满足条件,实现MultipartResolver接口:
而该接口的实现类SpringMVC也已经提供CommonsMultipartResolver

具体步骤:(直接使用CommonsMultipartResolver实现上传)
a.jar
commons-fileupload.jar
commons-io.jar
b.配置CommonsMultipartResolver
  将其加入SpringIOC容器
  
  <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
      <property name="defaultEncoding" value="UTF-8"></property>
      <!-- 上传单个文件的最大值,单位Byte;如果-1,表示无限值 -->
      <property name="maxUploadSize" value="102400"></property>
  </bean>
  
c.处理方法

@RequestMapping(value="testUpload")
    public String testUpload(@RequestParam("desc")String desc,@RequestParam("file")MultipartFile file) throws IOException {
        
        System.out.println("文件描述信息:"+desc);
        //jsp中上传的文件:file
        
        InputStream input = file.getInputStream();//IO
        
        String fileName  = file.getOriginalFilename();
        
        OutputStream out = new FileOutputStream("e:\\"+fileName);//IO
        
        byte[] bs = new byte[1024];
        int len =  -1;
        while((len=input.read(bs))!=-1){
            out.write(bs,0,len);
        }
      out.close();
      input.close();
        //将file上传到服务器中的某一个 硬盘文件中
      System.out.println("上传成功");
        
        return "success2";
    }
    
     <form action="SpringMVCHandler/testUpload" method="post" enctype="multipart/form-data">
            <input type="file" name="file"/>    
            描述:<input name="desc" type="text"/>
            <input type="submit" value="上传">
     </form>
          

2.拦截器
  原理与过滤器相同
SpringMVC:要想实现拦截器,必须实现一个接口HandlerInterceptor  

a.编写拦截器implements HandlerInterceptor
b.配置:将自己写的拦截器配置到springmvc中(spring)

如果有多个拦截器,则每个拦截器的preHandle postHandle 都会在相应时机各被触发一次;但是afterCompletion只在最后一次拦截被触发进行渲染


3.异常处理
SpringMVC: HandlerExceptionResolver接口,

该接口的每个实现类都是异常的一种处理方式:

a.
ExceptionHandlerExceptionResolver:主要提供了@ExceptionHandler注解,并通过该注解处理异常

//该方法 可以捕获本类中 抛出的ArithmeticException异常
    @ExceptionHandler({ArithmeticException.class,ArrayIndexOutOfBoundsException.class})
    public String handlerArithmeticException(Exception e){
           System.out.println(e);
           return "error";
    }

@ExceptionHandler标识的方法的参数必须在异常类型(Throwable或其子类),不能包含其他类型参数


异常处理路径:最短优先

@ExceptionHandler默认只能捕获当前类中的异常方法。
如果发现异常的方法和处理异常的方法不在同一个类中:@ControllerAdvice

总结:如果一个方法用于处理异常,并且只处理当前类中的异常:@ExceptionHandler
      如果一个方法用于处理异常,并且处理所有类中的异常:类前加@ControllerAdvice、处理异常的方法前加@ExceptionHandler

b.
ResponseStatusExceptionResolver:自定义异常显示界面@ResponseStatus

@ResponseStatus(value=HttpStatus.FORBIDDEN,reson="数组越界")
public class MyArrayIndexOutOfBoundsException extends Exception{ //自定义异常
}

@ResponseStatus也可以标志在方法前面


视频学习地址:https://ke.qq.com/course/list/DT

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值