• SpringMVC小结


    入门程序

    1. 创建maven项目需要选择webapp骨架(org.apache.maven.archetypes:maven-archetype-webapp),还有添加额外配置(archetypeCatalog  internal),防止创建maven的web项目慢的问题。
    2. 引入依赖(修改maven的jdk编译环境为1.8)
        spring-context
        spring-web
        spring-webmvc
        servlet-api(scope--->provide)
        jsp-api(scope--->provide)
     3. 核心配置文件的配置(mvc和context约束)
        1. 开启注解扫描 <context:component-scan base-package />
        2. 视图解析器对象 <bean class="InternalResourceViewResolver"> 拼接字符串的前面 和 拼接字符串的后面的两个set </bean>
        3. 开启SpringMVC框架注解支持 <mvc:annotation-driven/>
    4. web.xml的配置
        1. 配置前端控制器,加载核心配置文件
            <servlet>
                <servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name>
                <url-pattern>/</url-pattern>
            </servlet-mapping>
    5. 编写Controller和jsp页面进行测试
        1. 使用@Controller注解和jsp配置视图解析器进行测试
        2. 使用@RestController进行测试(推荐,相对简单)
    

    MVC的执行流程

    1. 配置文件的加载:
        启动项目,加载web.xml文件
            创建Servlet(前端/核心控制器-->指挥中心)的对象
            springmvc.xml的加载
                注解扫描加载SpringIOC的bean(@Controller) 
                视图解析器
                SpringMVC注解支持(@RequestMapping)
    2. 请求响应:
        客户端发送请求------> 核心控制器(进入SpringMVC的请求流程)----->
        调用HandlerMapping(处理器映射器),匹配被@Controller注解注解的类中的@RequestMapping -----> 
        调用HandlerAdapter(处理器适配器)执行handle(Controller中声明的方法),handle返回结果(ModelAndView,模型视图,封装结果和视图)给HandlerAdapter ------->
        HandlerAdapter返回MOdelAndView给核心控制器,核心控制器拿到结果去找视图解析器(ViewResolver)进行视图解析----->
        视图解析器进行物理拼接形成具体的路径(View),返回给核心控制器 ------> 
        核心控制器进行视图渲染,填充数据到reuqest域中,response响应返回给客户端
    3. 组件介绍
        前端/核心控制器: 中央调度,协调作用
        处理器映射器(HanderMapping): 根据请求的url查找Handler
        处理器适配器(HanderAdapter): 执行Handle
        ModelAndView: 模型及视图,封装结果视图
        ViewResolver: 视图解析器,解析逻辑视图
        Handle: 程序员编写业务逻辑处理,也就是Controller的方法
    

    请求参数绑定

    1. 基本数据类型绑定:
        原则: 请求后拼接的参数与handle的参数名保持一致
    2. JavaBean对象的绑定
        1. 简单Bean直接使用form表单,name属性的值为Bean对象的属性名
        2. Bean内包含另一个Bean,name的值使用属性.属性的方式
        3. list使用属性下标点属性 ------> list[0].name
        4. map使用属性key属性的方式  -----> list['one'].name
        
    3. 中文乱码问题:
        post乱码可以在web.xml中配置Spring提供的CharacterEncodingFilter
        get乱码:
            tomcat8之前,在tomcat的配置文件中配置URIEncoding="utf-8"
            new String(username.getBytes("ios-8859-1"),"UTF-8")的方式
            
    4. 日期类型转换:
        1. 自定义类实现Converter<S,T>接口,使用DateFormat进行格式的转换.
        2. 在springmvc中配置自定义转换器(ConversionServiceFactoryBean).
            * 注意是context包下的转换器
            * 配置converters属性
            * 注入自定义转换器的bean
    

    SpringMVC使用原生的Servlet

    Handler方法的形参设置HttpServletRequest和HttpServletResponse就可以获取到所有的原生Servlet对象了
    

    注解介绍

    1. @RequestMapping:
        * 作用位置:
            1. 类上: 窄化请求路径,业务隔离
            2. 方法上: url请求映射
        * 属性:
            1. value: 指定请求路径,与path属性一样
            2. method: 指定请求方式,值有GET,POST,DELETE等等(枚举类型,RequestMethod)
            3. params: 用于指定限制请求参数条件
            4. headers: 用于指定请求头
            
    2. @RequestParam:
        * 作用 : 在页面传递的参数名与后台不一致的时候需要使用该注解,作用于参数之前
        * 属性 :
            1. name/value : 指定页面传递的参数名
            2. required : 是否为必须,默认为true,表示该参数必须传递
            3. defaultValue : 给定参数一个默认值,当有默认值的时候required属性感觉就无效了
            
    3. @RequestBody
        * 作用: 用于获取请求体的内容.(get请求不适用,POST请求适用)
            
    4. @PathVariable(基于Restful风格的url支持) 
        * 作用在参数之前,目的是获取请求url中的占位符(参数)的信息
            /test/{sid} ---->  请求路径
            @PathVaribale(name="sid") Integer id ---> 方法的参数
            /test/10  ----> 客户端的访问路径
        * Restful的理解:
            通过请求参数决定对哪个资源进行操作
            通过请求方式决定采用何种操作(post,delete,put,get)
            
    5. HiddenHttpMethodFilter:
        浏览器的form表单只支持get和post请求,要洗那个发送put或delete请求,需要借助SpringMVC提供的HiddenHttpMethodFilter.
        使用: 
            1. 在web中配置HiddenHttpMethodFilter过滤器
            2. 在表单中添加隐藏域,<input type="hidden" name="_method" value="PUT"/>
            3. 定义handle,声明method为RequestMethod.PUT
            
    6. @RequestHeader
        用于获取请求消息头,作用在方法参数之前
        value属性可以指定获取哪个请求头信息(User-Agent比较常用)
        
    7. @CookieValue
        * 获取指定名称cookie的值
        * value属性指定cookie名称(JSESSIONID)
        
    8. @ModelAttribute
        * 作用位置:
            1. 方法上: 被@ModelAttribute注解修饰的方法表示该方法会在当前Controller的人格一个方法执行前先执行
                应用在表单提交实体数据不完整的情况下,为实体数据添加内容.
                    方法有返回值(直接返回user),springmvc会将方法执行的返回值,存放在Model对象,最终会存放在Request中:
                        考虑在修改的时候根据id获取实体,方法返回实体,前台只需要传递修改的内容就可以了.
                    方法无返回值,springmvc会将方法形参中的map中的数据存放在Model对象,最终会存放在Request中:
                        在方法中使用map保存数据,在Handler的参数前使用@ModelAttribute(name="key")获取
            2. 形式参数前(需制定value(key)属性):
                获取request中获取对应的value的数据
                
    9. @SessionAttributes(只能作用于类上,指定属性)
        * 用于多个Handler间的参数共享(将数据存放在session域)
        * 使用Model对象的addAttribute方法存放数据
        * 使用ModelMap对象的get方法来获取session数据
        * 使用setComplete()方法清空session域的数据(使用的是SessionStatus对象)
    

    Handler返回值类型

    1. 字符串:简单字符串是逻辑视图名称
        * 使用返回的字符串,经过视图解析器,拼接前缀后缀,跳转到真实路径
    2. void ===> 原始的Servlet操作
        * 请求路径默认是: 前缀 + handle访问路径 + 后缀
        * 使用原生Servlet进行跳转和携带参数,但是注意这个时候不会执行ViewResolver,所以必须写全路径,这个需要注意.在handle最后加个return;防止handle跳转方法完成后继续执行后续的代码.
        * 还有需要注意重定向是无法访问WEB-INF目录下的东西.
        * 直接响应数据: response.getWriter().print("content");注意处理乱码问题
    3. ModelAndView
        * ModelAndView对象: ModelAndView mv = new ModelAndView();
        * 可以存放数据到对象,使用mv.addObject("key","value");实际还是存放在Model中,最后还是request域中
        * 存放跳转的页面: 使用mv.setViewName("success");
    4. forward和redirect关键字的用法(返回类型还是String):
        * 返回的写法不一样,有了forward关键字后就不能调用视图解析器.
            return "forward:/WEB-INF/pages/success.jsp"
        * return "redirect:/index.jsp"; 重定向不能直接跳转到WEB-INF的目录下,并且redirect关键字不用添加项目目录
        * return "forward:testString"; 转发到指定的的Handle
          return "redirect:/user/testString";重定向到指定的的Handle
    

    响应JSON数据

    1. 在springmvc配置文件中配置静态资源不拦截(因为前端控制器会拦截所有资源):
        <mvc:resources mapping="/js/**" location="/js/" />,表示js文件下面的所有文件都不拦截
        <mvc:resources mapping="/css/**" location="/css/" />
        <mvc:resources mapping="/images/**" location="/images/" />
        > 注意静态资源放在web-app下
        
        上面的配置在mapping的后面也一定要加**,否则会失败(在我电脑上是这样),如果还是失败,可以试试在web.xml中配置:
        <servlet-mapping>
    		<servlet-name>default</servlet-name>
    		<url-pattern>*.js</url-pattern>
    	</servlet-mapping>
        
    2. ajax请求返回json数据:
        * $.ajax({
            url:"user/testAjax",
            type:"POST",
            contentType:"application/json;charset=utf-8",
            data:'{"username":"hehe","password":"123456","age":24}',
            dataType:"json",
            success:function(data){
                alert(data);
            }
            
          })
    3. 自动转换,将json字符串转换为对象,需要额外依赖jackson的jar包:
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.7</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-core</artifactId>
          <version>2.9.7</version>
        </dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-annotations</artifactId>
          <version>2.9.7</version>
        </dependency>
        
        接收json数据需要使用 ==@RequestBody==
            获取请求中的数据
            如果请求的参数是json格式,使用pojo接受,但是注意参数名和实体属性名一致
            
        响应json数据需要使用 ==@ResponseBody==
            直接将方法执行的返回值响应给客户端
            如果是pojo,将pojo对象转化为json字符串
    

    传统方式文件上传(了解):

    1. 表单的enctype属性取值必须是: multipart/form-data
       method属性值必须是post
       提供你文件选择域: <input type="file" />
    2. 三方组件实现,引入额外依赖:
        commons-fileupload
        commons-io
    3. 传统方式文件上传(后台代码实现):
        创建文件的上传路径(path),使用request.getSession().getServletContext().getRealPath("/uploads");
        核心解析器:
            DiskFileItemFactory ---> 磁盘文件的工厂对象
            ServletFileUpload ---> 文件上传的核心解析器,传入工厂对象
        解析request对象
            List<FileItem> list = ServletFileUpload.parseRequest(request);
        文件上传:
            遍历list,判断是否为普通表单项(isFormFiled),不是则进行上传
            获取文件上传名,修改上传名为唯一上传名(考虑使用UUID或者日期)
            fileItem.write(new File(path,filename));path表示父级目录,filename表示修改后的文件名.
            最后使用fileItem.delete(); 用来删除临时文件
            
        /**
         * 文件上传
         * @return
         */
        @RequestMapping("/fileupload1")
        public String fileuoload1(HttpServletRequest request) throws Exception {
            System.out.println("文件上传...");
    
            // 使用fileupload组件完成文件上传
            // 上传的位置
            String path = request.getSession().getServletContext().getRealPath("/uploads/");
            // 判断,该路径是否存在
            File file = new File(path);
            if(!file.exists()){
                // 创建该文件夹
                file.mkdirs();
            }
    
            // 解析request对象,获取上传文件项
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 解析request
            List<FileItem> items = upload.parseRequest(request);
            // 遍历
            for(FileItem item:items){
                // 进行判断,当前item对象是否是上传文件项
                if(item.isFormField()){
                    // 说明普通表单向
                }else{
                    // 说明上传文件项
                    // 获取上传文件的名称
                    String filename = item.getName();
                    // 把文件的名称设置唯一值,uuid
                    String uuid = UUID.randomUUID().toString().replace("-", "");
                    filename = uuid+"_"+filename;
                    // 完成文件上传
                    item.write(new File(path,filename));
                    // 删除临时文件
                    item.delete();
                }
            }
    
            return "success";
        }
    

    SpringMVC的文件上传(掌握)

    1. springmvc.xml配置文件上传解析器:
        类为CommonsMultipartResolver
        id为multipartResolver,这个不能改变(这个很重要)
        属性为:maxUploadSize,值为10485760
        <!--配置文件上传解析器-->
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize" value="10485760"/>
        </bean>
        
    2. handler的形参: (HttpServletRequest request,MultipartFile upload)
        表单的隐藏域的name属性必须和handler的形参MultipartFile的对象的名字一样.
        <form action="/file/fileupload" method="post" enctype="multipart/form-data">
            文件上传:<input type="file" name="upload">
            <input type="submit" value="提交">
        </form>
    3. handler的步骤:
        1. 创建文件上传目录path
        2. 获取文件名,修改文件名为唯一名字
        3. 使用upload.transferTo(new File(newFileName))就完成了
        
            @RequestMapping("fileupload")
            public String fileUpload(HttpServletRequest request, MultipartFile upload) throws Exception {
                // 创建文件上传目录
                String realPath = request.getSession().getServletContext().getRealPath("/uploads/");
                // 创建File
                File file = new File(realPath);
                // 判断目录是否存在
                if(!file.exists()){
                    // 创建该文件夹
                    file.mkdirs();
                }
                // 获取文件名,并修改文件名为唯一
                String name = upload.getOriginalFilename();
                // 生成uuid
                String replace = UUID.randomUUID().toString().replace("-", "");
                // 唯一文件名
                String fileName = replace + "_" + name;
                // 拼接最后的路径
                String newPath = realPath + fileName;
        
                // 进行文件的上传
                upload.transferTo(new File(newPath));
        
        
                return "hello";
            }
    

    SpringMVC跨服务器方式的文件上传

    1. 搭建图片服务器
        1. 修改tomcat端口号(修改3个地方)
        2. 修改tomcat的conf下的web.xml,修改readonly属性为false
        3. 在webapps下新建uploads目录
    2. 加入依赖:
        jersey-core
        jersey-client
    3. 步骤:
        创建客户端的对象Client.create()
        和图片服务器建立连接(client.resource())
        上传文件(webResource.put(new File(newFileName)))
        
        @RequestMapping("/fileupload3")
        public String fileuoload3(MultipartFile upload) throws Exception {
            System.out.println("跨服务器文件上传...");
    
            // 定义上传文件服务器路径
            String path = "http://localhost:9090/uploads/";
    
            // 说明上传文件项
            // 获取上传文件的名称
            String filename = upload.getOriginalFilename();
            // 把文件的名称设置唯一值,uuid
            String uuid = UUID.randomUUID().toString().replace("-", "");
            filename = uuid+"_"+filename;
    
            // 创建客户端的对象
            Client client = Client.create();
    
            // 和图片服务器进行连接
            WebResource webResource = client.resource(path + filename);
    
            // 上传文件
            webResource.put(upload.getBytes());
    
            return "success";
        }
    

    SpringMVC的异常处理

    1. 不处理异常造成的问题:
        * 用户体验差
        * 系统安全性容易出现问题
    2. 处理:
        1. 编写自定义异常处理类,继承Exception
            public class MyException extends Exception {
                private String msg;
                public MyException(String msg) {
                    this.msg = msg;
                }
                public String getMsg() {
                    return msg;
                }
                public void setMsg(String msg) {
                    this.msg = msg;
                }
            }
        2. 编写异常处理器,实现HandlerExceptionResolver
            public class MyExceptionResolver implements HandlerExceptionResolver {
                @Override
                public ModelAndView resolveException(HttpServletRequest httpServletRequest,
                                                     HttpServletResponse httpServletResponse,
                                                     Object o,
                                                     Exception e) {
                    // 创建自定义异常类
                    MyException myException = null;
                    // 转换
                    if(e instanceof MyException){
                        myException = (MyException)e;
                    } else{
                        myException = new MyException("程序遇到错误,但不是自定义异常类");
                    }
                    // 创建ModelAndView
                    ModelAndView mv = new ModelAndView();
                    mv.addObject("errormsg",myException.getMsg());
                    mv.setViewName("error");
                    return mv;
                }
            }
        3. 配置异常处理器,SpringMVC中配置异常处理器(也就是声明Bean)
            <!--配置异常处理器 -->
            <bean id="myExceptionResolver" class="com.itheima.exception.MyExceptionResolver"></bean>
        4. Controller如何进行编写呢?
            @RequestMapping("exce")
            public String testException() throws MyException {
                try {
                    int i = 1 / 0;
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new MyException("程序错误");
                }
                return "hello";
            }
    

    SpringMVC的拦截器

    1. 拦截器: 对处理器进行预处理和后处理(AOP的思想)
    2. 拦截器链: 多个拦截器按一个次序形成一个链,执行顺序考虑栈的结构,前置代码是入栈,后置代码是出栈
    3. 过滤器(filter)与拦截器(interceptor):
        过滤器什么都可以拦截,并且是属于servlet的,任何项目都可以用
        拦截器属于SpringMVC的,只有在SpringMVC的项目中使用,并且只能拦截控制器的访问
    4. 使用拦截器的步骤:
        1. 编写拦截器: 类实现HandlerInterceptor,实现3个方法:
            boolean preHandler(): 预处理,handler执行前执行
                true: 放行,如果有多个拦截器,放行到下一个拦截器,没有后续拦截器,执行Handler方法
                false: 不放行, 到此为止,不继续向下执行
            postHandler(): 后处理,handler之后,跳转页面之前执行
            afterComletion(): 最后执行的方法,也就是成功返回页面后执行的代码
            
            public class MyInterceptor implements HandlerInterceptor {
                /**
                 * Handler执行之前执行
                 * @param request
                 * @param response
                 * @param handler
                 * @return
                 * @throws Exception
                 */
                @Override
                public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                    System.out.println("preHandle=======================");
                    return true;
                }
            
                /**
                 * Handler执行之后,跳转页面之前
                 * @param request
                 * @param response
                 * @param handler
                 * @param modelAndView
                 * @throws Exception
                 */
                @Override
                public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
                    System.out.println("postHandle=======================");
                }
            
                /**
                 * 跳转页面之后执行
                 * @param request
                 * @param response
                 * @param handler
                 * @param ex
                 * @throws Exception
                 */
                @Override
                public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                    System.out.println("afterCompletion=============================");
                }
            }
        2. 配置拦截器: 
            <mvc:interceptors>
                <!--可以配置对个interceptor,表示多个拦截器-->
                <mvc:interceptor>
                    <!--拦截的具体方法-->
                    <mvc:mapping path="/**"/>  <!--所有的方法都拦截-->
                    <!--不要拦截的具体方法,和上面那个配置一个就好-->
                    <!-- <mvc:exclude-mapping path=""/>-->
                    <!--配置拦截器对象-->
                    <bean class=""/>
                </mvc:interceptor>
               
            </mvc:interceptors>
            
            
             <!--配置拦截器-->
            <mvc:interceptors>
                <mvc:interceptor>
                    <mvc:mapping path="/**"/>
                    <bean class="com.itheima.interceptor.MyInterceptor"/>
                </mvc:interceptor>
            </mvc:interceptors>
            
            
        3. 前端:
            <% System.out.println("hello.jsp================"); %>
            
            执行效果:
                preHandle=======================
                interceptor===================
                postHandle=======================
                hello.jsp================
                afterCompletion=============================
    5. 拦截器的作用:
        登录拦截器=======> 在prehandler()方法中获取session,判断有无用户,无用户跳转到登录.
  • 相关阅读:
    C++中用Int转成bool时,只有0是false,其他都是true。这个和其他语言很不一样,注意不要掉坑里了。
    C# 获取动态验证码?
    Silverlight单元格事件
    LDAPHelper
    Perl内部保留变量(系统变量)
    WebSphere MQ基础命令
    老鼠, 老虎傻傻分不清楚之Double.NaN
    TextBlock or Label?
    如何阅读代码
    EDID
  • 原文地址:https://www.cnblogs.com/wadmwz/p/9785596.html
Copyright © 2020-2023  润新知