application.yaml中修改访问前缀以及映射路径。
spring:
mvc:
static-path-pattern: /res/**#但是这个会影响欢迎页面和favicon.ico图标的的加载
web:
resources:
static-locations: [classpath:/haha/]
https://www.webjars.org/可以得到静态资源的maven文件
访问webjars里面的jar包,要用webjars/jquery/3.6.0/jquery.js这样的路径jquery/3.6.0/jquery.js是要访问的文件,webjars相当于默认前缀
欢迎页面不能设置访问前缀,不然会导致访问失效
禁用掉所有静态资源规则
spring:
web:
resources:
add-mappings: false
表单提交现在只有post和get方法,怎么发出put和delete请求:
现版本是:表单继续使用post请求,但是再使用一个
<input name="_method" type="hidden" value="DELETE">
标签放在这个表单中,就能实现delete提交,把value设置为put就能实现put请求,这个在源码中有体现。这个设置好后还需在properties文件中设置为true,因为底层源码默认为false。
spring:
mvc:
hiddenmethod:
filter:
enabled: true
对于每一个请求的参数,都有required方法,设置成false的话,有没有都行,true就是必须有,没有就报错。
@GetMapping、@PostMapping、@PutMapping、@DeleteMapping
这四个是四种请求方式,相当于在@RequestMapping
里面的method等于他们这四个
可以修改它默认的_method参数,从原理得知,当@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})这个条件满足时才会new一个,因此我们自己创建一个,因为它的创建不依赖其他的,可设置proxyBeanMethods = false,轻量级,使用以下代码创建后setMethodParam就可以把它改为我们自己想设置的参数。
@Configuration(proxyBeanMethods = false)
public class Webconfig {
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter Filter=new HiddenHttpMethodFilter();
Filter.setMethodParam("_m");
return Filter;
}
}
对于网页参数接收的几种方式:
HTML测试代码:
<body>
<h1>Cqupt欢迎您</h1>
<form method="post" action="/user">
<input value="post提交" type="submit">
</form>
<form method="get" action="/user">
<input value="get提交" type="submit">
</form>
<form method="post" action="/user">
<input name="_m" type="hidden" value="DELETE">
<input value="delete提交" type="submit">
</form>
<form method="post" action="/user">
<input name="_m" type="hidden" value="put">
<input value="put提交" type="submit">
</form>
<ul>
<a href="/car/1/owner/syf?age=18&interest='篮球'&interest='乒乓'">传参</a>
<li>@PathVarible(路径变量)</li>
<li>@RequestHeadler(获取请求头)</li>
<li>@RequestParam(获取请求参数)</li>
<li>@CookieValue(获取Cookie值)</li>
<li>@RequestAttribute(获取request域属性)</li>
<li>@RequestBody(获取请求体)</li>
<li>@MatrixVariable(矩阵变量)</li>
</ul>
<form action="/save" method="post">
测试@RequestBody(获取请求体)<br>
用户名<input name="username"><br>
邮箱<input name="email">
<input type="submit" value="提交">
</form>
</body>
controller代码:
@RestController
public class ParameterController {
/**
* /car/1/owner/syf?age=18&interest='篮球'&interest='乒乓'
*定义方法时取得的参数里面的Map只能是<String,String>,没加参数用map就相当于把里面的key:value都一一配对存放
*PathVariable()括号中放GetMapping("/car/{id}/owner/{username}")里{}的参数名,再定义变量就行,取出来的就是这个值
* PathVariable获取网址信息中参数,RequestHeader获取请求头
* 当网页中有请求参数时单个的可用RequestParam,当一个interest有多个值可用List集合,也可用一个map把所有参数的值都获取到里面
*/
@GetMapping("/car/{id}/owner/{username}")//必须按照这个顺序发送参数,{}中是变参,owner是不变的
public Map<String ,Object> getCar(@PathVariable("id") Integer id, @PathVariable("username") String username,
@PathVariable Map<String,String> map1, @RequestHeader("User-Agent")String header,
@RequestHeader Map<String,String> mapheader, @RequestParam("age")String age,
@RequestParam("interest") List<String> list,@CookieValue("Idea-fc47497d")String cookie,
@CookieValue("Idea-fc47497d") Cookie allKookie){
Map<String,Object> map=new HashMap<>();
map.put("id",id);
map.put("username",username);
map.put("map1",map1);
map.put("User-Agent",header);
map.put("allheader",mapheader);
map.put("age",age);
map.put("list",list);
map.put("Idea-fc47497d",cookie);
System.out.println(allKookie.getValue());
return map;
}
@PostMapping("/save")
public Map<String,Object> postMethod(@RequestBody String body){//将请求信息都获取到,key=value&key=value这种形式
Map<String,Object> map=new HashMap<>();
map.put("body",body);
return map;
}
}
网页转发信息Controller代码:
//转发到另一个页面 注意!!类上是@Controller,最后显示的是被转发页面要展示的信息
@GetMapping("/goto")
public String page(HttpServletRequest request){
request.setAttribute("msg","成功了");
request.setAttribute("code","java-开发");
return "forward:/success"; //转发到 /success请求
}
//被转发的加上@ResponseBody
@ResponseBody
@GetMapping("/success")
public Map<String,Object> success(@RequestAttribute("msg")String msg,//不能用Map把RequestAttribute的内容全部放一起
@RequestAttribute("code")String code,
HttpServletRequest request){
Map<String,Object> map=new HashMap<>();
map.put("msg",msg);
map.put("code",code);
map.put("msg1",request.getAttribute("msg"));
map.put("code1",request.getAttribute("code"));
return map;
}
矩阵变量:
矩阵变量url中带分号的形式,分号后面为矩阵变量,前面为要访问的路径
//下面两种方法都可以开启 矩阵变量功能,默认是关闭的
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper=new UrlPathHelper();
//不移除矩阵变量后面的分号,矩阵变量的功能就能实现 默认是移除
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
};
}
// @Override
// public void configurePathMatch(PathMatchConfigurer configurer) {
// UrlPathHelper urlPathHelper=new UrlPathHelper();
// //不移除矩阵变量后面的分号,矩阵变量的功能就能实现 默认是移除
// urlPathHelper.setRemoveSemicolonContent(false);
// configurer.setUrlPathHelper(urlPathHelper);
// }
Html代码:
<a href="/cars/sel;low=34;brand=byd,wuling">@MatrixVariable(矩阵变量)</a><br>
<a href="/cars/sel;low=34;brand=byd,brand=wuling">@MatrixVariable(矩阵变量</a><br>
<a href="/boss/1;age=20/2;age=25">@MatrixVariable(矩阵变量</a>
java代码:
//1、语法/cars/sel;low=34;brand=byd,wuling
//2、Spring Boot 默认禁用掉了矩阵变量
// 手动开启:原理。对于路径的处理,UrlPathHelper进行解析
// removeSemicolonContent(移除分号)支持矩阵变量的
//两个变量名一致 就需要加变量名 @MatrixVariable(value = "age",pathVar = "bossid"),只有一个的话直接写矩阵变量名就行
// 3、矩阵变量必须有url路径变量才能被解析
//注意!!!!类上要有@ResponseBody标签
@GetMapping("/cars/{path}")
public Map<String,Object> car1(@MatrixVariable("low") Integer s, @MatrixVariable("brand")List<String> brands,
@PathVariable("path") String path){
Map<String,Object> map=new HashMap<>();
map.put("low",s);
map.put("brands",brands);
map.put("path",path);
return map;
}
@GetMapping("/boss/{bossid}/{emplyid}")
public Map<String,Object> boss1(@MatrixVariable(value = "age",pathVar = "bossid") Integer bossid,
@MatrixVariable(value = "age",pathVar = "emplyid")Integer employid){
Map<String,Object> map=new HashMap<>();
map.put("bossid",bossid);
map.put("emplyid",employid);
return map;
}
html代码:
//表单可以级联使用例如下表形式
<form action="/saveuser" method="post">
姓名: <input name="username" value="zhangsan"><br>
年龄: <input name="age" value="23"><br>
生日: <input name="birth" value="1998"><br>
宠物姓名:<input name="pet.name" value="tom"><br>
宠物年龄:<input name="pet.age" value="2"><br>
<input type="submit" value="提交">
</form>
Controller代码:
/**
* 数据绑定: 页面提交的请求数据(get、post)都可以和对象属性进行绑定
* @param person
* @return
* 不能直接访问/saveuser网址,因为没有数据,会报错,要从表单那面提交过来看,报错信息:
* Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported]
*/
@PostMapping("/saveuser")
public Person Register(Person person){
return person;
}
给网页返还json对象代码:
@Controller
public class ResponseTestController {
//加上ResponseBody就能自动给前端返回数据,但是类上面就不能加了,类上就写Controller,类上加了这里就不加
//RequestResponseBodyMethodProcessor调用messageConverter 写成了json
@ResponseBody
@GetMapping("/test")
public Person GetPerson(){
Person person=new Person();
person.setAge(23);
person.setBirth("1998");
person.setPet(new Pet());
person.setUsername("syf");
return person;
}
内容协商
根据客户端接收能力不同,返回不同媒体类型的数据
确定客户端接收什么样的数据是通过请求头的accept字段确定的,看客户端接收的优先级,如果高xml而且服务器能够产生xml就返还,xml的文件依赖:
因为有了parent管理版本,不需要标注版本号。
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
测试浏览器时想观看效果,可通过以下方式实现:
# 内容协商 设置成true后在浏览器搜索栏加上 ?format=xml就能设置想接收什么形式,但是spring boot里面源码就支持json 和 xml 类似http://localhost:8080/test?format=json
#之前是通过请求头的accept字段确定,现在通过请求头中的format的值。相当于我们的参数优先。
spring:
mvc:
contentnegotiation:
favor-parameter: true
响应数据
自定义返回数据类型
1、先创建一个自己想写出数据类型的Convertor,实现HttpMessageConverter。
/**
* 自定义的Converter
*/
public class MyappMessageConverter implements HttpMessageConverter<Person> {
@Override//读就是能否读出传过来的参数
public boolean canRead(Class<?> aClass, MediaType mediaType) {
return false;
}
//只要方法返回的是Person类型就可以写
@Override
public boolean canWrite(Class<?> aClass, MediaType mediaType) {
return aClass.isAssignableFrom(Person.class);
}
/**
* 服务器要统计所有MessageConverter都能写出哪些内容类型,所以要把我们的注入进去
* 【application/x-myapp】
* @return
*/
@Override
public List<MediaType> getSupportedMediaTypes() {
return MediaType.parseMediaTypes("application/x-myapp");
}
@Override
public Person read(Class<? extends Person> aClass, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
/**
* 自定义协议的写出
* @param person
* @param mediaType
* @param httpOutputMessage
* @throws IOException
* @throws HttpMessageNotWritableException
*/
@Override
public void write(Person person, MediaType mediaType, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
String data=person.getUsername()+";"+person.getAge()+";"+person.getBirth()+";"+person.getPet();
OutputStream body=httpOutputMessage.getBody();
body.write(data.getBytes());
body.flush();
body.close();
}
}
最后在Config配置标签类中添加WebMvcConfigurer 组件重写extendMessageConverters方法,将自己创建的Convertor放进去
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer() {
//自定义的信息转换器
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MyappMessageConverter());
}
}
自定义url使用参数返回类型:
/**
* 自定义协商策略
* 用参数在url上定义新的策略达到能够用format=xxx实现
* 有可能我们添加的自定义功能会覆盖很多默认功能,导致一些默认的功能失效
* @param configurer
*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
//填入策略支持的媒体类型
Map<String, MediaType> mediaTypes=new HashMap<>();
mediaTypes.put("json",MediaType.APPLICATION_JSON);
mediaTypes.put("xml",MediaType.APPLICATION_XML);
//放入新的"x"为新设置的format=x
mediaTypes.put("x",MediaType.parseMediaType("application/x-myapp"));
//指定支持解析哪些参数的哪些媒体类型
ParameterContentNegotiationStrategy strategy=new ParameterContentNegotiationStrategy(mediaTypes);
//如果只定义了以上就只设置参数策略就失去了请求头的,因为重写了之后自己没有写
//改变format为for 没有写就默认为 format
strategy.setParameterName("for");
//加上默认请求头的
HeaderContentNegotiationStrategy headstrategy=new HeaderContentNegotiationStrategy();
configurer.strategies(Arrays.asList(strategy,headstrategy));
}