【springmvc框架一文搞定】

SpringMVC框架

  • 1. 搭建springmvc测试项目
    • 1.1 创建maven项目
    • 1.2 导入依赖pom.xml
    • 1.3 将springmvc容器加载到tomcat中
    • 1.4 启动tomcat插件
    • 1.5 访问路径:
  • 2. 剖析启动过程
    • 2.1 启动服务器初始化过程
    • 2.2 访问路径执行过程
  • 3.spring-springmvc bean的管理
    • 3.1 因为功能不同,如何避免spring错误的加载到?
    • 3.2 spring加载与spring相关的bean
    • 3.3 springmvc加载springmvc相关的bean
    • 3.4 将springmvc与spring的bean加载到服务tomcat容器中
    • 3.5 启动tomcat插件
    • 3.6 查看打印日志
    • 3.7 当我们自己编写一个容器的时候,并且注册进去
  • 4. 请求与响应
    • 4.1 请求映射路径
    • 4.2 请求参数
    • 4.3 日期类型参数传递
    • 4.4 响应json数据
  • 5. 拦截器interceptor
    • 5.1 实现HandlerInterceptor,创建自己的拦截器,实现自己的特定业务(权限)
    • 5.2将自定义的拦截器注册进去[两种方案]
    • 5.3 拦截器执行顺序

1. 搭建springmvc测试项目

1.1 创建maven项目

1.2 导入依赖pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.ypygroupId>
    <artifactId>springmvc_01_quickstartartifactId>
    <version>1.0-SNAPSHOTversion>
    <packaging>warpackaging> 

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    properties>
    <dependencies>
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.1.0version>
            <scope>providedscope>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.2.12.RELEASEversion>
        dependency>
    dependencies>
        
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.mavengroupId>
                <artifactId>tomcat7-maven-pluginartifactId>
                <version>2.2version>
                <configuration>
                    <port>80port>
                    <path>/path>
                configuration>
            plugin>
        plugins>
    build>
project>

1.3 将springmvc容器加载到tomcat中

public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
    @Override
    protected WebApplicationContext createServletApplicationContext() {
    	// 项目使用注解配置Web应用上下文
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        // 将配置类注册到上下文
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }

    @Override
    // 配置拦截路径,哪些访问路径需要springmvc管理
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    // 配置其他容器上下文
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

扫描controller进入容器

@ComponentScan("com.ypy.controller")
public class SpringMvcConfig {
}

控制器类

@Controller
public class UserController {

    @RequestMapping("/save")
    @ResponseBody
    public String save(){
        System.out.println("user save ...");
        return "{'info':'Springmvc'}";
    }
}

1.4 启动tomcat插件

edit configurations -> 搜maven -> run: tomcat7:run --> apply. --> run (绿色三角)启动

1.5 访问路径:

http://localhost/save
返回:
【springmvc框架一文搞定】_第1张图片

2. 剖析启动过程

2.1 启动服务器初始化过程

  1. 服务器启动,执行ServletContainerInitConfig类,初始化web容器
  2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象
  3. 加载SpringMvcConfig
  4. 执行@ComponentScan加载对应的bean
  5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法
  6. 执行getServletMappings方法,定义所有的请求都通过SpringMVC
    【springmvc框架一文搞定】_第2张图片

2.2 访问路径执行过程

  1. 发送请求localhost/save
  2. web容器发现所有请求多经过springmvc,将请求交给springmvc处理
  3. 解析请求路径/save
  4. 有/save匹配执行对应的方法save()
  5. 执行save()
  6. 检测有@RequestBody直接将save()方法的返回值作为响应体返回给请求方。

3.spring-springmvc bean的管理

1.springmvc会加载controller相关的bean
2. spring会加载service、dao、config等包下的bean,那么就会扫描根包下的所有子包,这样就会重复

3.1 因为功能不同,如何避免spring错误的加载到?

SpringMVC的bean–加载Spring控制的bean的时候排除掉springmvc控制的bean

方法:

  1. Spring加载的bean设定扫描范围为com.itheima,排除掉controllert包内的bean
  2. Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
  3. 不区分Spring与SpringMVC的环境,加载到同一个环境中

3.2 spring加载与spring相关的bean

@Configuration
//@ComponentScan({"com.ypy.service","com.ypy.dao"})
@ComponentScan(value = "com.ypy",
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ANNOTATION,
                classes = {Controller.class,RestController.class}
        )
)
public class SpringConfig {
}

3.3 springmvc加载springmvc相关的bean

@ComponentScan("com.ypy.controller")
public class SpringMvcConfig {
}

3.4 将springmvc与spring的bean加载到服务tomcat容器中

public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        System.out.println("1被调用了);
        return new Class[]{SpringConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
    	System.out.println("2被调用了);
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
       	System.out.println("3被调用了);
        return new String[]{"/"};
    }
}

或者

public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
   // 注册springmvc容器bean
   @Override
   protected WebApplicationContext createServletApplicationContext() {
       AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
       ctx.register(SpringMvcConfig.class);
       return ctx;
   }

   @Override
   protected String[] getServletMappings() {
       return new String[]{"/"};
   }

   // 注册spring的容器bean
   @Override
   protected WebApplicationContext createRootApplicationContext() {
       AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
       ctx.register(SpringConfig.class);
       return ctx;
   }
}

3.5 启动tomcat插件

同上,启动方式
edit configurations -> 搜maven -> run: tomcat7:run --> apply. --> run (绿色三角)启动

3.6 查看打印日志

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< com.ypy:springmvc_01_quickstart >-------------------
[INFO] Building springmvc_01_quickstart 1.0-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO] 
[INFO] >>> tomcat7-maven-plugin:2.2:run (default-cli) > process-classes @ springmvc_01_quickstart >>>
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ springmvc_01_quickstart ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ springmvc_01_quickstart ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 5 source files to D:\Application\WorkSpace\self-learn\base-learn\springmvc_01_quickstart\target\classes
[INFO] 
[INFO] <<< tomcat7-maven-plugin:2.2:run (default-cli) < process-classes @ springmvc_01_quickstart <<<
[INFO] 
[INFO] 
[INFO] --- tomcat7-maven-plugin:2.2:run (default-cli) @ springmvc_01_quickstart ---
[INFO] Running war on http://localhost:80/
[INFO] Using existing Tomcat server configuration at D:\Application\WorkSpace\self-learn\base-learn\springmvc_01_quickstart\target\tomcat
[INFO] create webapp with contextPath: 
十一月 13, 2023 9:47:44 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-bio-80"]
十一月 13, 2023 9:47:44 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service Tomcat
十一月 13, 2023 9:47:44 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet Engine: Apache Tomcat/7.0.47
十一月 13, 2023 9:47:45 下午 org.apache.catalina.core.ApplicationContext log
信息: 1 Spring WebApplicationInitializers detected on classpath
1被调用了
2被调用了
3被调用了
十一月 13, 2023 9:47:45 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring root WebApplicationContext
[INFO] Root WebApplicationContext: initialization started
[INFO] Root WebApplicationContext initialized in 261 ms
[INFO] Initializing Servlet 'dispatcher'
十一月 13, 2023 9:47:45 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring DispatcherServlet 'dispatcher'
[INFO] Completed initialization in 119 ms
十一月 13, 2023 9:47:45 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-bio-80"]
// 发送请求,打印的输出结果
user save ...

3.7 当我们自己编写一个容器的时候,并且注册进去

import com.ypy.config.SpringConfig;
import com.ypy.config.SpringMvcConfig;
import com.ypy.controller.UserController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main(String[] args) {
    	// 创建一个internal container
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        // 注册配置类
        ctx.register(SpringConfig.class, SpringMvcConfig.class);
        // 刷新容器
        ctx.refresh();
        //容器获取bean
        UserController bean = ctx.getBean(UserController.class);
        System.out.println(bean);
    }
}

// 输出结果:
com.ypy.controller.UserController@64c87930

4. 请求与响应

4.1 请求映射路径

@RequestMapping(“/模块”),可以放在方法上和类上。
@ResponseBody 作为响应返回

4.2 请求参数

@GetMapping 接收参数:发送请求时直接拼接在url上,接收参数的方法,直接写在方法形参上
@PostMapping 接收参数:请求时使用x-www-form-urlencoded,form-data 还可以发送file。如果是参数接收,直接将String param, int param 写在方法形参上

如果发送post请求,发送了中文汉字,会出现乱码问题,之前设置过滤器解决,现在在springmvc配置中解决

// 配置springmvc文件
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    //乱码解决
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}
1. 单个参数:请求传递参数和控制器方法的参数名不一样,可以使用@RequestParam("")指定
2. 实体参数: 直接将请求传递参数封装到了实体类中(参数对应上)
3. 嵌套POJO参数:如果实体里面还有一个引用类型参数,传参的时候继续协商引用类型的参数.属性 
			(address.city / address.provice)
4. 数组参数:请求传递参数时传递同样的参数名likes(爱好),后端控制器方法的String[] likes 就会收集到
5. 集合参数:请求传递参数时传递同样的参数名likes(爱好),后端控制器方法的List[] likes 就会收集到,
			发现报错了,原因是springmvc 以为是引用类型,创建类型-> 设置属性,但是我们是将数据
			塞进List中去。解决方案是:@RequestParam
6. JSON数据参数:
		body -> row -> json
		springmvc需要开启json->转换为对象的功能之一. @EnableWebMvc
		@RequestBody List<String> likes

4.3 日期类型参数传递

日期类型是2023/11/15,直接传递给后天控制器Date date,可以转换成功
如果是其他分隔符,就会报string -> Date 类型转换不匹配异常
解决方案:@DateTimeFormat(pattern = “yyyy-mm-dd”)
前后端的日期格式统一

4.4 响应json数据

  • 页面的跳转
    【springmvc框架一文搞定】_第3张图片
	@RequestMapping("toPage")
    public String toPage(){
        return "page.jsp";
    }

POM文件配置


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.ypygroupId>
    <artifactId>request_mappingartifactId>
    <version>1.0.0version>
    <packaging>warpackaging>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    properties>
    <dependencies>
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>javax.servlet-apiartifactId>
            <version>3.1.0version>
            <scope>providedscope>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.2.12.RELEASEversion>
        dependency>
    dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.mavengroupId>
                <artifactId>tomcat7-maven-pluginartifactId>
                <version>2.2version>
                <configuration>
                    <port>80port>
                    <path>/path>
                configuration>
            plugin>
        plugins>
    build>
project>

效果页面
在这里插入图片描述

  • 响应文本数据
	@RequestMapping("/test")
    @ResponseBody
    public String test() {
        System.out.println("test");
        return "{'msg':'testMsg'}";
    }
  • 响应json数据
	@RequestMapping("/test")
    @ResponseBody
    public User test() {
        return  new User('张三', 25);
    }

响应json不是spirngmvc完成的,是jackson包做的工作。

5. 拦截器interceptor

5.1 实现HandlerInterceptor,创建自己的拦截器,实现自己的特定业务(权限)

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandler --> ");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandler -->");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion -->");
    }
}

5.2将自定义的拦截器注册进去[两种方案]

  • 方式一: 继承WebMvcConfigurationSupport,无需配置@EnableWebMvc
import com.ypy.controller.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import javax.annotation.Resource;

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Resource // 注入自己的拦截器
    private MyInterceptor myInterceptor;

    @Override // 访问静态资源,路径跳转
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
    }

    @Override   // 注册自己的拦截器进去,设置拦截路径
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
    }
}

配置扫描

@Configuration
@ComponentScan({"com.ypy.controller", "com.ypy.config"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
}

tomcat 启动的时候,将配置类扫描进去

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class}; // main 
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    //乱码解决
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}
  • 第二种方案:实现WebMvcConfigurer, 需要开启@EnableWebMvc
@Configuration
@ComponentScan({"com.ypy.controller"/*, "com.ypy.config"*/})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
    @Resource
    private MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
    }
}

5.3 拦截器执行顺序

  • 配置多个拦截器时,形成拦截器链
  • 拦截器的运行顺序参照拦截器添加顺序为准。
    【springmvc框架一文搞定】_第4张图片

你可能感兴趣的:(spring全家桶,java,SpringMVC)