SpringMVC

作者: AIGame孑小白 | 来源:发表于2021-05-19 08:07 被阅读0次

    什么是MVC?

    Model View Controller

    • 表现层

      • mvc是表现层的设计模型,和其他层次没有关系
    • 业务层

      • Service(功能开发都是在这里编写)
    • 持久层

      • dao层(数据持久化)

    SpringMVC

    简而言之:SpringMVC是用来处理http请求的。

    重要组件:

    • DispatcherServlet:前端控制器,接受所有请求(@WebServlet配置为’/‘时不包含jsp)
    • HandlerMapping:解析请求格式(判断希望执行那个具体的方法)
    • HandlerAdapter:负责调用具体的方法
    • ViewResovler:视图解析器,跳转到具体的视图文件

    第一个SpringMVC项目

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
       http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
        <servlet>
            <servlet-name>springmvc123</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>springmvc123</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    

    springmvc.xml

    <?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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
        <bean id="demo123" class="mvc01.DemoController"></bean>
        <!-- 用来解析请求 -->
        <bean  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <!-- 需要对urlMap设值注入 -->
            <property name="urlMap">
                <map>
                    <!-- key指的是解析出来控制器逻辑名 
                    value:往哪个控制器走...<bean>
                    -->
                    <entry key="demo" value-ref="demo123"></entry>
                </map>
            </property>
        </bean>
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
        <!-- 配置一个视图解析器,自动补充前缀和后缀 -->
        <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/"></property>
            <property name="suffix" value=".jsp"></property>
        </bean>
    </beans>
    

    编写控制器

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    
    public class DemoController implements Controller{
        @Override
        public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
            System.out.println("执行了SpringMVC的控制器");
            ModelAndView modelAndView = new ModelAndView("index");
            return modelAndView;
        }
    }
    

    看到这一行代码:返回一个ModelAndView可以直接跳转转发到对应的界面,参数就是页面路径。

    ModelAndView modelAndView = new ModelAndView("index");
    return modelAndView;
    

    由于我们做了如下配置:

    <!-- 配置一个视图解析器,自动补充前缀和后缀 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    

    所以在 new ModelAndView 的时候填写“index”即可。

    注解方式环境搭建

    配置mvc

    <mvc:annotation-driven></mvc:annotation-driven>
    

    这个注解实际上就包含了HandlerMapping的实现类:DefaultAnnotationHandlerMapping,不仅如此还配置了一个AnnotationMethodHandlerAdapter,也就是说:配置这一个标签,就相当于配置了这两个类。(包:org.springframe.web.servlet.mvc.annotation)

    编写Controller

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class DemoController {
        @RequestMapping("demo")
        public String demo(){
            System.out.println("执行demo");
            return "main.jsp";
        }
    }
    

    取消静态资源的拦截

    但是静态资源也会被拦截,我们可以告诉mvc哪些资源是静态资源,不需要拦截:

    <!-- 告诉mvc哪些资源是静态的,不要拦截 -->
    <mvc:resources location="" mapping="/js/**"></mvc:resources>
    

    表示:WebContent下面js文件夹下的所有文件

    mapping="/js/*"
    

    表示:WebConten下面js文件夹下的所有子文件以及子目录

    mapping="/js/**"
    

    所以一般配置都是两个"*"号

    location="/WEB-INF/"
    

    指的是在WEB-INF目录下面。

    基本类型或对象参数

    还是先配置web.xml

    <servlet>
        <servlet-name>springmvc123</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>springmvc123</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- 字符编码过滤器 -->
    <filter>
        <filter-name>encoding</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>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    上面已经配置了字符集的过滤器。

    springmvc.xml

    <beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
            ">
        <!-- 扫描包 -->
        <context:component-scan base-package="cn.jxb"></context:component-scan>
        <!-- 注解驱动 -->
        <mvc:annotation-driven></mvc:annotation-driven>
    </beans>
    

    创建一个People的类,写好getXXX()setXXX()方法。

    public class People {
        private String name;
        private int age;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
    

    编写Controller

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class DemoController {
        @RequestMapping("demo")
        public String demo(People p){
            System.out.println("执行demo,名称:"+p.getName()+",年龄:"+p.getAge());
            return "main.jsp";
        }
    }
    

    我们在demo方法中的参数由Spring自动帮我们传递,除了这些我们需要的参数以外,Servlet原生的所有相关类,基本都可以拿来使用,例如:

    public String demo(ServletRequest request,HttpSession session){
        System.out.println("Request:"+request+",Session:"+session);
        return "main.jsp";
    }
    

    假如前端页面传过来的参数名称为"name1,age1",我们如果不想使用前端的名称,此时我们可以自己配置注解:

    <form action="demo" method="post">
    名称:<input type="text" name="name1"/>
    年龄:<input type="text" name="age1"/>
    <input type="submit" value="点击提交"/>
    </form>
    

    这样编写Controller:

    public String demo(@RequestParam("name1") String name,@RequestParam("age1") int age){
        System.out.println("执行demo,名称:"+name+",年龄:"+age);
        return "main.jsp";
    }
    

    该注解还有个功能就是增加默认值:

    @RequestParam(defaultValue="name1")
    

    比如我们在做分页的时候,就可以直接这样写入默认值,避免了大量的if判断。

    @RequestParam(required=true)
    

    假如这里设置为treu则表示必须要传入该参数!假如我们需要一个sql的条件语句,则可以使用这个强制要求必须传入参数,否则就报错(页面505)。

    复杂参数

    假如我们需要接收一个这样的复杂对象:

    <form action="demo" method="post">
    名称:<input type="text" name="name"/>
    年龄:<input type="text" name="age"/>
    <input type="checkbox" name="hover" value="吃饭" />
    <input type="checkbox" name="hover" value="睡觉" />
    <input type="checkbox" name="hover" value="打游戏" />
    <input type="submit" value="点击提交"/>
    </form>
    

    那么我们必须要这样配置:

    @Controller
    public class DemoController {
        @RequestMapping("demo")
        public String demo(String name,int age,@RequestParam("hover")List<String> ho){
            System.out.println("执行demo,名称:"+name+",年龄:"+age+"集合:"+ho);
            return "main.jsp";
        }
    }
    

    那么假如我们请求的参数是这样的:

    <form action="demo" method="post">
    名称:<input type="text" name="peo.name"/>
    年龄:<input type="text" name="peo.age"/>
    <input type="submit" value="点击提交"/>
    </form>
    

    现在我们的参数名称改变为了"peo.name"这样的参数,那么我们如何接收呢?

    首先我们已经拥有了People类:

    public class People {
        private String name;
        private int age;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
    

    然后我们可以创建一个Demo类,来装载peo对象:

    public class Demo {
        private People peo;
    
        public People getPeo() {
            return peo;
        }
        public void setPeo(People peo) {
            this.peo = peo;
        }
    }
    

    然后我们这样配置Cotroller:

    @Controller
    public class DemoController {
        @RequestMapping("demo")
        public String demo(Demo demo){
            System.out.println(demo);
            return "main.jsp";
        }
    }
    

    基于上面的拓展,假如我们的参数变成这样:

    <form action="demo" method="post">
    名称:<input type="text" name="peo[0].name"/>
    年龄:<input type="text" name="peo[0].age"/>
    <br>
    名称:<input type="text" name="peo[1].name"/>
    年龄:<input type="text" name="peo[1].age"/>
    <br>
    <input type="submit" value="点击提交"/>
    </form>
    

    那么我们只需要对Demo类进行修改即可:

    public class Demo {
        private List<People> peo;
        @Override
        public String toString() {
            return "Demo [peo=" + peo + "]";
        }
        public List<People> getPeo() {
            return peo;
        }
        public void setPeo(List<People> peo) {
            this.peo = peo;
        }
    }
    

    restful风格参数

    <a href="demo/张三/13">点击我啊</a>
    
    @RequestMapping("demo/{peopleName}/{peopleAge}")
    public String demo(@PathVariable("peopleName")String name,@PathVariable("peopleAge")int age){
        System.out.println(name+":"+age);
        return "/main.jsp";
    }
    
    • @RequestMapping("demo/{peopleName}/{peopleAge}")参数对应请求格式,并且在下面的参数中使用。

    • @PathVariable("peopleName")这个注解时,名称也需要对应。

    • return "/main.jsp"这里的路径需要改写成相对于目录的路径,前面加个"/"即可。

    跳转方式

    我们默认的请求方式是请求转发,如果想使用重定向可以在return的参数中添加"redirect:"例如:

    return "redirect:/main.jsp";
    

    如果需要使用转发(默认的,不用配置)添加"forward:资源路径"

    自定义视图解析器

    SpringMVC为我们配置了默认的视图解析器。不过我们可以自己在springmvc.xml中配置:

    <!-- 自定义视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    

    然后我们就可以在Controller中简单的转发到main.jsp:

    @RequestMapping("demo/{peopleName}/{peopleAge}")
    public String demo(@PathVariable("peopleName")String name,@PathVariable("peopleAge")int age){
        System.out.println(name+":"+age);
        return "main";
    }
    

    转发到第二个控制器

    @RequestMapping("demo")
    public String demo(){
        System.out.println("转发到ok控制器");
        return "forward:ok";
    }
    @RequestMapping("ok")
    public String ok(){
        System.out.println("转发到我这里啦");
        return "main";
    }
    

    当我们在浏览器中输入"demo"回车后,会自动转发到"ok"控制器上,然后"ok"控制器会访问"/main.jsp"这段参数是在springmvc.xml中< bean>中配置的前后缀名称。

    @ResponseBody

    我们之前使用Servlet实现向页面打印数据:

    @Controller
    public class DemoController {
        @RequestMapping("demo")
        public void demo(HttpServletResponse response) throws IOException{
            PrintWriter writer =  response.getWriter();
            writer.append("OKKKKK");
            writer.flush();
            writer.close();
        }
    }
    

    现在我们要是想输出数据:

    @Controller
    public class DemoController {
        @RequestMapping("demo")
        @ResponseBody
        public People demo(){
            People people = new People();
            people.setName("张三");
            people.setAge(13);
            return people;
        }
    }
    

    注意:@ResponseBody这个注解底层使用了jackson解析对象,将对象解析成json字符串打印到网页上面,所以需要导入相关jar包。

    {"name":"张三","age":13}
    

    通过@RequestMapping参数,produces="text/html;charset=utf-8":可以配置响应头(Content-Type)信息,进而解决中文乱码的问题:

    @RequestMapping(value="demo",produces="text/html;charset=utf-8")
    @ResponseBody
    public String demo(){
        return "我是中文";
    }
    

    SpringMVC基本运行原理

    如果在web.xml 中设置DispatcherServlet 的< url-pattern>为/时,当用户发起请求, 请求一个控制器, 首先会执行 DispatcherServlet. 由DispatcherServlet调用HandlerMapping的DefaultAnnotationHandlerMapping 解 析 URL, 解 析 后 调 用HandlerAdatper 组 件 的AnnotationMethodHandlerAdapter 调 用Controller 中的 HandlerMethod.当 HandlerMethod 执行完成后会返回View,会被 ViewResovler 进行视图解析,解析后调用 jsp 对应的.class 文件并运行,最终把运行.class 文件的结果响应给客户端

    相关文章

      网友评论

        本文标题:SpringMVC

        本文链接:https://www.haomeiwen.com/subject/dqgyjltx.html