SpringMVC

1 项目搭建

1.1 运行原理

        Servlet容器中的SpringMVC核心前端控制器DispatcherServlet会拦截所有请求,将拦截的请求与@RequestMapping进行匹配,将请求交给匹配的Controller方法进行处理

1.2 创建web容器

        初始化Servlet容器(web容器),用web配置类的方式替代web.xml(创建一个类继承AbstractDispatcherServletInitializer并重写方法)

/**
 * 初始化Servlet容器,即web容器(替代web.xml)
 */
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    /**
     * 加载SpringMVC对应的容器对象
     * SpringMVCIOC容器是SpringIOC的子容器(子容器可以引用父容器,反之则不行)
     */
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(SpringConfig.class);
        return context;
    }

    /**
     * 哪些请求归SpringMVC处理
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};//表示所有请求都贵SpringMVC处理
    }

    /**
     * 加载Spring对应的容器对象
     * 可以将Spring和SpringMVC的容器对象合并成只有SpringMVC容器对象,因此此方法可以返回null即可
     */
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

        简化开发(创建一个类继承AbstractAnnotationConfigDispatcherServletInitializer )

/**
 * 初始化Servlet容器,即web容器(替代web.xml)
 */
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    /**
     * 加载SpringMVC对应的容器对象
     * SpringMVCIOC容器是SpringIOC的子容器(子容器可以引用父容器,反之则不行)
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    /**
     * 被Servlet容器拦截的哪些请求归SpringMVC处理
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    /**
     * 加载Spring对应的容器对象
     * 可以将Spring和SpringMVC的容器对象合并成只有SpringMVC容器对象,因此此方法可以返回null即可
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    /**
     * 配置过滤器
     *      编码过滤器(过滤器会优先拦截器执行):解决post乱码问题
     */
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        return new Filter[]{filter};
    }

    /**
     * 配置文件上传解析器
     *      不是用的:org.springframework.web.multipart.commons.CommonsMultipartResolver(额外导包commons-fileupload)
     *      而是用的:org.springframework.web.multipart.support.StandardServletMultipartResolver(SpringMVC自带)
     */
    @Override
    protected void customizeRegistration(ServletRegistration.Dynamic registration) {
        super.customizeRegistration(registration);
        String location = "";
        long maxFileSize = 20971520;  //文件大小限制byte(20M)
        long maxRequestSize = 41943040;  //请求大小限制byte(40M)
        int fileSizeThreshold = 0;  //文件大小阈值
        registration.setMultipartConfig(new MultipartConfigElement(location, maxFileSize, maxRequestSize, fileSizeThreshold));//配置对multipart的支持
    }
}

1.3 常用注解

分类注解说明
@RequestMapping(path="/path",method=RequestMapping.POST)

映射请求(用在"类/方法"上)

@GetMapping=@RequestMapping(method=RequestMapping.GET)

@PostMapping

@DeleteMapping

@PutMapping

接收@RequestHeader("请求头key")接收请求头中的参数
@RequestParam("userNmae") String name给Controller类方法形参起别名
@DatetimeFormat(pattern="yyyy-MM-dd HH:mm:ss:SSS")

可以用在pojo类的属性上,将属性接收的对应格式的字符串转换为Date

也可以用在Controller方法形参前,接收对应格式的字符串转换为Date

@RequestBody User user接收POST请求体中的JSON字符串,并封装到JavaBean中
@PathVariableRESTful方式,接收"路径变量"
响应@ResponseBody将"类/方法"返回的数据转换为JSON对象
@RestController用在类上,相当于@Controller+@ResponseBody

        注解选择:

                请求参数有多个时,将多个参数写成json格式,后台以json格式接收,@RequestBody使用广泛

                请求参数非json时,用@RequestParam接收

                请求参数通常只有1个时,可以用@PathVariable接收 

1.4 代码示例

@Controller
public class TeacherController {

    private static final Logger log = LoggerFactory.getLogger(TeacherController.class);

    @Autowired
    private TeacherService userService;

    @RequestMapping("/save")
    @ResponseBody
    public Teacher save(@RequestBody Teacher teacher) {
        teacher.setName("王五");
        teacher.setAge(44);
        teacher.setPosition("英语老师");
        log.info(String.valueOf(teacher));
        return teacher;
    }
}

2 REST风格

        REST(Representational State Transfer)表现层资源状态转换

        RESTful按照REST风格访问资源

2.1 资源访问对比

        (1) 传统风格

                http://localhost/user/getById?id=1    //查询用户(GET请求)

                http://localhost/user/deleteById?id=1    //删除用户(GET请求)

                http://localhost/user/addUser    //新增用户(POST请求)

                http://localhost/user/updateUser    //修改用户(POST请求)

        (2) REST风格

                http://localhost/users/1    //查询用户删除用户

                http://localhost/users    //添加用户修改用户

        REST风格通常在的映射地址后加s(此s不是复数形式,而是style的缩写,例如users)

        REST风格优点:书写简化,隐藏访问路径(更加安全)

2.2 实现原理

        REST风格访问资源是用行为动作进行区分,可以用同一个请求路径,实现不同的功能

                http://localhost/users/1    GET方式(查询),DELETE方式(删除)

                http://localhost/users       POST方式(新增),PUT方式(修改)

2.3 示例代码

        前端代码:

addTeacher() {
	axios.post("/teachers", {
		position: '体育老师',
		name: '赵四',
		age: 54
	}, {
		headers: {
			'Content-Type': 'application/json'
		}
	}).then(response => {
		alert(response.data)
	})
},
updateTeacher() {
	axios.put("/teachers", {
		position: '物理老师',
		name: '龙武',
		age: 77
	}, {
		headers: {
			'Content-Type': 'multipart/form-data'
		}
	}).then(response => {
		alert(response.data)
	})
},
deleteTeacher(){
	axios.delete("/teachers/lisa/66", {
	}, {
		headers: {
			'Content-Type': 'application/json'
		}
	}).then(response => {
		alert(response.data)
	})
},
queryTeacher(){
	axios.get("/teachers/gods", {
	}, {
		headers: {
			'Content-Type': 'application/json'
		}
	}).then(response => {
		alert(response.data)
	})
},
queryAllTeacher(){
	axios.get("/teachers", {
	}, {
		headers: {
			'Content-Type': 'application/json'
		}
	}).then(response => {
		alert(response.data)
	})
}

        后台代码:

@RestController
@RequestMapping("/teachers")
public class TeacherController {

    @Autowired
    private TeacherService teacherService;

    private static final Logger log = LoggerFactory.getLogger(TeacherController.class);

    @PostMapping
    public String add(@RequestBody Teacher teacher) {
        log.info("新增teacher信息为:" + teacher);
        return "{'info':'add success'}";
    }

    @PutMapping
    public String update(@RequestParam String position, @RequestParam String name, @RequestParam Integer age) {
        Teacher teacher = new Teacher();
        teacher.setPosition(position);
        teacher.setName(name);
        teacher.setAge(age);
        log.info("修改teacher为:" + teacher);
        return "{'info':'update success'}";
    }

    /**
     * {name}将"请求路径"倒数第二个作为路径变量
     * {age}将"请求路径"最后一个作为路径变量
     *
     * @PathVariable 接收名为id或age的路径变量
     */
    @DeleteMapping("/{name}/{age}")
    public String delete(@PathVariable String name, @PathVariable Integer age) {
        log.info("删除name为" + name + ",age为" + age + "的teacher");
        return "{'info':'delete success'}";
    }

    @GetMapping("/{name}")
    public String query(@PathVariable String name) {
        log.info("查询name为" + name + "的teacher");
        return "{'info':'query success'}";
    }

    @GetMapping
    public String queryAll() {
        log.info("查询全部的teacher");
        return "{'info':'query all success'}";
    }
}

3 放行访问

        因为所有的请求都会被Servlet容器拦截,而通过web配置类设置的又是将所有拦截的请求交给SpringMVC去处理,导致即使访问一些静态资源(html,css,js,img等)也会被拦截后交给SpringMVC处理,而SpringMVC通过请求路径映射又找不到对应的@RequestMaping,就会报404错误

        我们需要的是访问接口交给SpringMVC映射处理,访问静态资源放行,因此需要一个SpringMVESupport配置类继承WebMvcConfigurationSupport类,并重写addResourceHandlers方法

/**
 * 放行资源访问
 * 此类需要被SpringIOC容器扫描到
 */
@Configuration  //注意此类虽然用@Configuration注解了,但要区别于Spring容器的@Configuration,所以不能在Spring配置类中用@Import引入这个类,也不能Spring配置类自己继承WebMvcConfigurationSupport,而只能单独使用这个类并加上@Configuration
public class SpringMVCSupportConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        //被servlet拦截的"请求路径"如果是/html/**,不要被交给MVC处理,而是交给Tomcat处理(将/html/**请求放行,并用html目录下的资源去匹配)
        registry.addResourceHandler("/html/**").addResourceLocations("/html/");
        registry.addResourceHandler("/index.html").addResourceLocations("/index.html");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值