Spring Boot 技术探索

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

8、Spring Boot中@RequestMapping的使用

平台环境:

名称

版本号

Mac OS X

10.14.5

JDK

1.8.0_201

Apache Maven

3.6.0

IntelliJ IDEA

2019.1 (Ultimate Edition)

Spring Boot

2.1.6.RELEASE

  在Spring Boot 中,控制器Controller负责处理访问请求,只需使用@Controller标记一个类是Controller ,然后使用@RequestMapping和@RequestParam等一些注解用以定义URL请求和Controller方法之间的映射,这样的Controller就能被外界访问到。

  这里重点是@RequestMapping,因此使用@RestController来代替@Controller测试。

 

接收参数

方式1:

直接使用方法参数接收

package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class testController
{
    @RequestMapping("/index/{name2}/{age2}")
    public String testPage2(@PathVariable String name2, @PathVariable int age2)
    {
        return "name2=" + name2 + ", age2=" + age2;
    }
}

启动项目,浏览器访问:http://127.0.0.1:8080/index?name=aoo&age=99

显示:

name=aoo, age=99

 

方式2:

使用@PathVariable

package com.example.demo.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class testController
{
    @RequestMapping("/index/{name2}/{age2}")
    public String testPage2(@PathVariable String name2, @PathVariable int age2)
    {
        return "name2=" + name2 + ", age2=" + age2;
    }
}

启动项目,浏览器访问:http://127.0.0.1:8080/index/LiLei/88

显示:

name2=LiLei, age2=88

 

方式3:

使用Model类接收参数。

Model类User

package com.example.demo.model;

public class User
{
    private String userName;
    private int age;
    private String remark;

    public String getUserName()
    {
        return userName;
    }

    public void setUserName(String userName)
    {
        this.userName = userName;
    }

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    public String getRemark()
    {
        return remark;
    }

    public void setRemark(String remark)
    {
        this.remark = remark;
    }

    @Override
    public String toString()
    {
        return "userName:" + userName + ",age=" + age + ",remark=" + remark;
    }
}

 

新建测试方法,用User类接收参数。只要是和User属性同名的参数都会被自动填充到User 对象中。

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class testController
{
    @RequestMapping("/getUser")
    public User testPage3(User user)
    {
        return user;
    }
}

 

启动项目,浏览器访问:http://127.0.0.1:8080/getUser?userName=LiLei&age=88&remark=oop

显示:

{"userName":"LiLei","age":88,"remark":"oop"}

 


 

*号匹配

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class testController
{
    @RequestMapping("/*/admin")
    public String testPage4()
    {
        return "测试*匹配";
    }
}

 

启动项目,浏览器访问:http://127.0.0.1:8080/abcde/admin

显示:

测试*匹配

 


 

HttpServletRequest与HttpServletResponse

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class testController
{
    @RequestMapping("/test5")
    public String testPage5(HttpServletRequest request, HttpServletResponse response)
    {
        String name = request.getParameter("name");
        String age = request.getParameter("age");
        return "name5=" + name + ", age5=" + age;
    }
}

 

启动项目,浏览器访问:http://127.0.0.1:8080/test5?name=Sam&age=66

显示:

name5=Sam, age5=66

 


 

指定请求的method类型

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class testController
{
    @RequestMapping(value = "/test6", method = RequestMethod.GET)
    public String testPage6()
    {
        return "GET请求成功!";
    }

    @RequestMapping(value = "/test7", method = RequestMethod.POST)
    public String testPage7()
    {
        return "POST请求成功!";
    }
}

 

浏览器访问http://127.0.0.1:8080/test6

返回

GET请求成功!

 

浏览器访问http://127.0.0.1:8080/test7

返回

Request method 'GET' not supported

 

由于设置了method = RequestMethod.POST参数,所以这里不可以用浏览器地址直接访问。

改用MockMvc测试。

package com.example.demo;

import com.example.demo.controller.testController;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

@SpringBootTest
public class WebControllerTest
{
    private MockMvc mockMvc;

    @Before
    public void setUp()
    {
        mockMvc = MockMvcBuilders.standaloneSetup(new testController()).build();
    }

    @Test
    public void test7() throws Exception
    {
        String responseString = mockMvc.perform(MockMvcRequestBuilders.post("/test7")).andReturn().getResponse().getContentAsString();
        System.out.println(responseString);
    }
}

小技巧:在IDEA中,输入sout回车。会自动完成System.out.println();的输入。

 

代码解释:

  • .andReturn()表示返回执行请求的直接访问结果。
  • .getResponse()表示获取response结果。
  • .getContentAsString()表示将返回信息转换为字符串。

 

显示结果:

POST?????

 

原因:

SpringMVC的@ResponseBody注解使用的处理类为Spring的org.springframework.http.converter.StringHttpMessageConverter类,返回中文乱码的原因是其默认处理的字符集是ISO-8859-1。而ISO-8859-1是单字节编码,不能用来编码中文。

 

解决办法:

在控制器上加上@RequestMapping(value = "/test7", method = RequestMethod.POST, produces="text/html;charset=UTF-8")字符编码的注解。加上注解之后,中文乱码的问题得到了解决。

也可以设置为produces = MediaType.APPLICATION_JSON_UTF8_VALUE

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class testController
{
    @RequestMapping(value = "/test7", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String testPage7()
    {
        return "POST请求成功!";
    }
}

 

这里又有一个问题,刚才提到到了乱码原因是@ResponseBody注解的问题,但是这里没看到@ResponseBody的影子。经过研究发现在@RestController的源码里找到了@ResponseBody的引用。

package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

   /**
    * The value may indicate a suggestion for a logical component name,
    * to be turned into a Spring bean in case of an autodetected component.
    * @return the suggested component name, if any (or empty String otherwise)
    * @since 4.0.1
    */
   @AliasFor(annotation = Controller.class)
   String value() default "";
}

 

这里又有人提出通过设置response的编码格式为UTF-8来解决。

经过测试,无论是在处理请求的方法中这样设置:

@RequestMapping(value = "/rulelist", method = RequestMethod.GET)
@ResponseBody
public String getRuleList(HttpServletRequest request,
        HttpServletResponse response) {
    response.addHeader("Content-Type", "application/json;charset=UTF-8");
    return service.getRuleList();
}

 

还是在MockMVC中这样设置:

ResultActions resultActions = this.mockMvc.perform(post(requestUrl)
                                            .accept(MediaType.APPLICATION_JSON)
                                            .content(requestParam));
        resultActions.andReturn().getResponse().setCharacterEncoding("UTF-8");
        //添加断言
        resultActions.andDo(print()).andExpect(status().isOk());

 

都不能解决乱码的问题。

 

具体原因分析见参考资料:

https://www.cnblogs.com/kaiblog/p/7565231.html

https://www.cnblogs.com/chenloveslife/p/9538333.html

 


 

produces 参数

用于限定请求映射的媒体类型,可以是单个或者多个媒体类型。只有当Accept匹配到其中一个媒体类型时,才映射请求。同时它也影响返回的内容类型。例如,生成一个带有UTF-8编码的JSON响应,则应该使用org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE。

 

格式:

       produces = "text/plain"

       produces = {"text/plain", "application/*"}

       produces = MediaType.APPLICATION_JSON_UTF8_VALUE

 


 

consumes参数

用于限定请求映射的媒体类型,可以是单个或者多个媒体类型。只有当Content-Type匹配到其中一个媒体类型时,才映射请求。

格式:

       consumes = "text/plain"

       consumes = {"text/plain”, "application/*"}

 

例子:

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class testController
{
    @RequestMapping(value = "/test8", consumes="application/json", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String testPage8()
    {
        return "application/json请求成功!";
    }
}

方法仅处理request的Content-Type为“application/json”类型的请求。

 

测试:

@Test
public void test8() throws Exception
{
    String responseString = mockMvc.perform(MockMvcRequestBuilders.post("/test8").contentType(MediaType.APPLICATION_JSON)).andReturn().getResponse().getContentAsString();
    System.out.println(responseString);
}

 

输出:

application/json请求成功!

 


 

params 参数

仅处理请求中包含了名为“myParam”,值为“myValue”的请求,只有在发现每个参数都具有给定值时才映射请求。

 

例子:

package com.example.demo.controller;

import com.example.demo.model.User;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
public class testController
{
    @RequestMapping(value = "/test9", params="myParam=myValue", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String testPage9()
    {
        return "myParam=myValue请求成功!";
    }
}

 

测试:

浏览器访问:http://127.0.0.1:8080/test9

返回:

Parameter conditions "myParam=myValue" not met for actual request parameters:

 

浏览器访问:http://127.0.0.1:8080/test9?myParam=myValue

返回:

myParam=myValue请求成功!

 


 

headers 参数

仅处理请求中包含了My-Header=myValue的请求,只有在发现每个参数都具有给定值时才映射请求。

还支持媒体类型通配符(*),用于Accept和Content-Type等头部。例如,

@RequestMapping(value = "/something", headers = "content-type=text/*")

 

 


 

参考资料:

https://www.cnblogs.com/qq78292959/p/3760560.html

 

Bootstrap Thumbnail Second
MySQL

MySQL is the world's most popular open source database.

GO

Bootstrap Thumbnail Third
算法基础

本书介绍了什么是计算机算法,如何描述它们,以及如何来评估它们。

GO