文章目录
回顾@RequestMapping
继上一节的案例,上次知道执行流程后,我们可以继续学习,接下来映射传参
当然是离不开@RequestMapping
注解啦,源码以及注释如下
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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;
/**
* Annotation for mapping web requests onto specific handler classes and/or
* handler methods.
*
* <p>Handler methods annotated with this annotation can have very flexible
* signatures. The exact details of the supported method arguments and return
* values depend on the specific
* {@link org.springframework.stereotype.Controller @Controller} model supported.
* Both Spring Web MVC and Spring WebFlux support this annotation with some
* differences. More details are available in the Spring Framework reference.
*
* <p><b>NOTE:</b> {@code @RequestMapping} will only be processed if an
* an appropriate {@code HandlerMapping}-{@code HandlerAdapter} pair
* is configured. If you are defining custom {@code HandlerMappings} or
* {@code HandlerAdapters}, then you need to add {@code RequestMappingHandlerMapping}
* and {@code RequestMappingHandlerAdapter} to your configuration.</code>.
*
* <p><b>NOTE:</b> When using controller interfaces (e.g. for AOP proxying),
* make sure to consistently put <i>all</i> your mapping annotations - such as
* {@code @RequestMapping} and {@code @SessionAttributes} - on
* the controller <i>interface</i> rather than on the implementation class.
*
* @author Juergen Hoeller
* @author Arjen Poutsma
* @author Sam Brannen
* @since 2.5
* @see GetMapping
* @see PostMapping
* @see PutMapping
* @see DeleteMapping
* @see PatchMapping
* @see RequestParam
* @see RequestAttribute
* @see PathVariable
* @see ModelAttribute
* @see SessionAttribute
* @see SessionAttributes
* @see InitBinder
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
* @see org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
/**
* Assign a name to this mapping.
* <p><b>Supported at the type level as well as at the method level!</b>
* When used on both levels, a combined name is derived by concatenation
* with "#" as separator.
* @see org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder
* @see org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy
*/
String name() default "";
/**
* The primary mapping expressed by this annotation.
* <p>This is an alias for {@link #path}. For example
* {@code @RequestMapping("/foo")} is equivalent to
* {@code @RequestMapping(path="/foo")}.
* <p><b>Supported at the type level as well as at the method level!</b>
* When used at the type level, all method-level mappings inherit
* this primary mapping, narrowing it for a specific handler method.
*/
@AliasFor("path")
String[] value() default {};
/**
* In a Servlet environment only: the path mapping URIs (e.g. "/myPath.do").
* Ant-style path patterns are also supported (e.g. "/myPath/*.do").
* At the method level, relative paths (e.g. "edit.do") are supported within
* the primary mapping expressed at the type level. Path mapping URIs may
* contain placeholders (e.g. "/${connect}")
* <p><b>Supported at the type level as well as at the method level!</b>
* When used at the type level, all method-level mappings inherit
* this primary mapping, narrowing it for a specific handler method.
* @see org.springframework.web.bind.annotation.ValueConstants#DEFAULT_NONE
* @since 4.2
*/
@AliasFor("value")
String[] path() default {};
/**
* The HTTP request methods to map to, narrowing the primary mapping:
* GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
* <p><b>Supported at the type level as well as at the method level!</b>
* When used at the type level, all method-level mappings inherit
* this HTTP method restriction (i.e. the type-level restriction
* gets checked before the handler method is even resolved).
*/
RequestMethod[] method() default {};
/**
* The parameters of the mapped request, narrowing the primary mapping.
* <p>Same format for any environment: a sequence of "myParam=myValue" style
* expressions, with a request only mapped if each such parameter is found
* to have the given value. Expressions can be negated by using the "!=" operator,
* as in "myParam!=myValue". "myParam" style expressions are also supported,
* with such parameters having to be present in the request (allowed to have
* any value). Finally, "!myParam" style expressions indicate that the
* specified parameter is <i>not</i> supposed to be present in the request.
* <p><b>Supported at the type level as well as at the method level!</b>
* When used at the type level, all method-level mappings inherit
* this parameter restriction (i.e. the type-level restriction
* gets checked before the handler method is even resolved).
* <p>Parameter mappings are considered as restrictions that are enforced at
* the type level. The primary path mapping (i.e. the specified URI value)
* still has to uniquely identify the target handler, with parameter mappings
* simply expressing preconditions for invoking the handler.
*/
String[] params() default {};
/**
* The headers of the mapped request, narrowing the primary mapping.
* <p>Same format for any environment: a sequence of "My-Header=myValue" style
* expressions, with a request only mapped if each such header is found
* to have the given value. Expressions can be negated by using the "!=" operator,
* as in "My-Header!=myValue". "My-Header" style expressions are also supported,
* with such headers having to be present in the request (allowed to have
* any value). Finally, "!My-Header" style expressions indicate that the
* specified header is <i>not</i> supposed to be present in the request.
* <p>Also supports media type wildcards (*), for headers such as Accept
* and Content-Type. For instance,
* <pre class="code">
* @RequestMapping(value = "/something", headers = "content-type=text/*")
* </pre>
* will match requests with a Content-Type of "text/html", "text/plain", etc.
* <p><b>Supported at the type level as well as at the method level!</b>
* When used at the type level, all method-level mappings inherit
* this header restriction (i.e. the type-level restriction
* gets checked before the handler method is even resolved).
* @see org.springframework.http.MediaType
*/
String[] headers() default {};
/**
* The consumable media types of the mapped request, narrowing the primary mapping.
* <p>The format is a single media type or a sequence of media types,
* with a request only mapped if the {@code Content-Type} matches one of these media types.
* Examples:
* <pre class="code">
* consumes = "text/plain"
* consumes = {"text/plain", "application/*"}
* </pre>
* Expressions can be negated by using the "!" operator, as in "!text/plain", which matches
* all requests with a {@code Content-Type} other than "text/plain".
* <p><b>Supported at the type level as well as at the method level!</b>
* When used at the type level, all method-level mappings override
* this consumes restriction.
* @see org.springframework.http.MediaType
* @see javax.servlet.http.HttpServletRequest#getContentType()
*/
String[] consumes() default {};
/**
* The producible media types of the mapped request, narrowing the primary mapping.
* <p>The format is a single media type or a sequence of media types,
* with a request only mapped if the {@code Accept} matches one of these media types.
* Examples:
* <pre class="code">
* produces = "text/plain"
* produces = {"text/plain", "application/*"}
* produces = "application/json; charset=UTF-8"
* </pre>
* <p>It affects the actual content type written, for example to produce a JSON response
* with UTF-8 encoding, {@code "application/json; charset=UTF-8"} should be used.
* <p>Expressions can be negated by using the "!" operator, as in "!text/plain", which matches
* all requests with a {@code Accept} other than "text/plain".
* <p><b>Supported at the type level as well as at the method level!</b>
* When used at the type level, all method-level mappings override
* this produces restriction.
* @see org.springframework.http.MediaType
*/
String[] produces() default {};
}
可见:
//可以作用于类或者方法上都可以,path,和value作用相同都是映射路径注解,请求能有写多种请求方式
//方法传递可以传参数,也可以传对象等
还是上次的工程:增加paramController类以及修改Index.jsp页面
package com.tho.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("params")
public class ParamController {
//可以作用于类或者方法上都可以,path,和value作用相同都是映射路径注解,请求能有写多种请求方式
//传递可以传参数,也可以传对象等
@RequestMapping("testparams")
public String testParam(){
System.out.println("@RequestMapping起作用了");
return "success";
}
}
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/13
Time: 22:32
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="hello">入门案例</a><br>
<a href="params/testparams">测试RequestMapping相关案例</a>
</body>
</html>
运行一下:
点测试RequestMapping相关案例链接
入门成功,主要的错误点基本和上一篇文章一样,不累述。
SpringMVC之传参使用
测试传参数属性
接下来修改,测试使用方法传参!修改ParamController类
package com.tho.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("params")
public class ParamController {
//可以作用于类或者方法上都可以,path,和value作用相同都是映射路径注解,请求能有写多种请求方式
//传递可以传参数,也可以传对象等
@RequestMapping("testparams")
public String testParam(String username){
System.out.println("@RequestMapping起作用了");
System.out.println("用户名:"+username);
return "success";
}
}
其实就是加入一个输出语句
System.out.println("用户名:"+username);
修改Index.jsp代码,使用传有username的链接
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="hello">入门案例</a><br>
<a href="params/testparams?username=zhangsan">测试RequestMapping相关案例</a>
</body>
</html>
运行测试:
请求方式也可以直接在注解里标明修改方法上的RequestMapping
@RequestMapping(value="testparams",method = RequestMethod.POST)
运行!
控制台没打印,说明我们的方法配置与请求不匹配,没有运行到方法,因为超链接使用的是get提交方式所以不成功,接下来改为get提交
package com.tho.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("params")
public class ParamController {
//可以作用于类或者方法上都可以,path,和value作用相同都是映射路径注解,请求能有写多种请求方式
//传递可以传参数,也可以传对象等
@RequestMapping(value="testparams",method = RequestMethod.GET)
public String testParam(String username){
System.out.println("@RequestMapping起作用了");
System.out.println("用户名:"+username);
return "success";
}
}
参数也传多个但是依旧传入这个username
运行
请求的url是如下
http://localhost:8080/springmvc_day01_01_start_war/params/testparams?username=zhangsan&password=123
也是可以执行的
去了Index.jsp的username属性,运行如下:
证明传参不影响@RequestMapping映射方法的使用,影响执行的是请求方式,当然传参没有我们想要的自然也达不到我们书写方法的目的!!
ok接下传一个对象
先建一个domain的包,创建Account类
package com.tho.domain;
public class Account {
private String username;
private String password;
private String money;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMoney() {
return money;
}
public void setMoney(String money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money='" + money + '\'' +
'}';
}
}
然后修改ParamController加入代码:
/**
* 把用户封装到javaBean的类当中
*
* @return
*/
@RequestMapping(value = "/saveAccount", method = RequestMethod.POST)
public String saveAccount(Account account) {
System.out.println("保存了账户");
System.out.println(account);
return "success";
}
启动项目:访问http://localhost:8080/springmvc_day01_01_start_war/params.jsp
测试get请求:一样是405
使用和映射方法一致的请求即post请求,输入参数则会被封装成对象
接下来演示对象的属性为对象或者是集合
先演示对象,模拟多表关系,账单用户多对一关系(映射时实际上是一笔订单对一个用户,即多对一相当于一对一的关系!)
domain包下创建User对象如下:
package com.tho.domain;
public class User {
private String uname;
private Integer age;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", age=" + age +
'}';
}
}
修改Accout类,加入User属性,同时修改原本的getter和setter以及toString方法
package com.tho.domain;
public class Account {
private String username;
private String password;
private String money;
//封装一个对象
private User user;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMoney() {
return money;
}
public void setMoney(String money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money='" + money + '\'' +
", user=" + user +
'}';
}
}
修改params.jsp加入User对象相关的属性输入框
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="params/saveAccount">get请求</a>
<form action="params/saveAccount" method="post">
用户名称:<input type="text" name="username"><br/>
用户密码:<input type="password" name="password"><br/>
用户金额:<input type="text" name="money"><br/>
用户姓名:<input type="text" name="user.uname"><br/>
用户年龄:<input type="text" name="user.age"><br/>
<input type="submit" value="保存账户,post 请求">
</form>
</body>
</html>
ParamController加入输出语句获得User对象
还是访问:http://localhost:8080/springmvc_day01_01_start_war/params.jsp
get就不测了,结果都知道,就填form表单然后提交过去给后台
整合对象模拟一对一,或者说多对一成功。注意前端页面的值应该写成属性User的对象user点上User类的属性。这样就能把User对象封装在account对象传给后台。
当然中文传输是会乱码的
解决中文乱码问题
接下来解决中文乱码问题!
spring框架为我们完成了这件事,即有一个专门正对编码乱码的过滤器类CharacterEncodingFilter
看看源代码:
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Servlet Filter that allows one to specify a character encoding for requests.
* This is useful because current browsers typically do not set a character
* encoding even if specified in the HTML page or form.
*
* <p>This filter can either apply its encoding if the request does not already
* specify an encoding, or enforce this filter's encoding in any case
* ("forceEncoding"="true"). In the latter case, the encoding will also be
* applied as default response encoding (although this will usually be overridden
* by a full content type set in the view).
*
* @author Juergen Hoeller
* @since 15.03.2004
* @see #setEncoding
* @see #setForceEncoding
* @see javax.servlet.http.HttpServletRequest#setCharacterEncoding
* @see javax.servlet.http.HttpServletResponse#setCharacterEncoding
*/
public class CharacterEncodingFilter extends OncePerRequestFilter {
@Nullable
private String encoding;
private boolean forceRequestEncoding = false;
private boolean forceResponseEncoding = false;
/**
* Create a default {@code CharacterEncodingFilter},
* with the encoding to be set via {@link #setEncoding}.
* @see #setEncoding
*/
public CharacterEncodingFilter() {
}
/**
* Create a {@code CharacterEncodingFilter} for the given encoding.
* @param encoding the encoding to apply
* @since 4.2.3
* @see #setEncoding
*/
public CharacterEncodingFilter(String encoding) {
this(encoding, false);
}
/**
* Create a {@code CharacterEncodingFilter} for the given encoding.
* @param encoding the encoding to apply
* @param forceEncoding whether the specified encoding is supposed to
* override existing request and response encodings
* @since 4.2.3
* @see #setEncoding
* @see #setForceEncoding
*/
public CharacterEncodingFilter(String encoding, boolean forceEncoding) {
this(encoding, forceEncoding, forceEncoding);
}
/**
* Create a {@code CharacterEncodingFilter} for the given encoding.
* @param encoding the encoding to apply
* @param forceRequestEncoding whether the specified encoding is supposed to
* override existing request encodings
* @param forceResponseEncoding whether the specified encoding is supposed to
* override existing response encodings
* @since 4.3
* @see #setEncoding
* @see #setForceRequestEncoding(boolean)
* @see #setForceResponseEncoding(boolean)
*/
public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {
Assert.hasLength(encoding, "Encoding must not be empty");
this.encoding = encoding;
this.forceRequestEncoding = forceRequestEncoding;
this.forceResponseEncoding = forceResponseEncoding;
}
/**
* Set the encoding to use for requests. This encoding will be passed into a
* {@link javax.servlet.http.HttpServletRequest#setCharacterEncoding} call.
* <p>Whether this encoding will override existing request encodings
* (and whether it will be applied as default response encoding as well)
* depends on the {@link #setForceEncoding "forceEncoding"} flag.
*/
public void setEncoding(@Nullable String encoding) {
this.encoding = encoding;
}
/**
* Return the configured encoding for requests and/or responses.
* @since 4.3
*/
@Nullable
public String getEncoding() {
return this.encoding;
}
/**
* Set whether the configured {@link #setEncoding encoding} of this filter
* is supposed to override existing request and response encodings.
* <p>Default is "false", i.e. do not modify the encoding if
* {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()}
* returns a non-null value. Switch this to "true" to enforce the specified
* encoding in any case, applying it as default response encoding as well.
* <p>This is the equivalent to setting both {@link #setForceRequestEncoding(boolean)}
* and {@link #setForceResponseEncoding(boolean)}.
* @see #setForceRequestEncoding(boolean)
* @see #setForceResponseEncoding(boolean)
*/
public void setForceEncoding(boolean forceEncoding) {
this.forceRequestEncoding = forceEncoding;
this.forceResponseEncoding = forceEncoding;
}
/**
* Set whether the configured {@link #setEncoding encoding} of this filter
* is supposed to override existing request encodings.
* <p>Default is "false", i.e. do not modify the encoding if
* {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()}
* returns a non-null value. Switch this to "true" to enforce the specified
* encoding in any case.
* @since 4.3
*/
public void setForceRequestEncoding(boolean forceRequestEncoding) {
this.forceRequestEncoding = forceRequestEncoding;
}
/**
* Return whether the encoding should be forced on requests
* @since 4.3
*/
public boolean isForceRequestEncoding() {
return this.forceRequestEncoding;
}
/**
* Set whether the configured {@link #setEncoding encoding} of this filter
* is supposed to override existing response encodings.
* <p>Default is "false", i.e. do not modify the encoding.
* Switch this to "true" to enforce the specified encoding
* for responses in any case.
* @since 4.3
*/
public void setForceResponseEncoding(boolean forceResponseEncoding) {
this.forceResponseEncoding = forceResponseEncoding;
}
/**
* Return whether the encoding should be forced on responses.
* @since 4.3
*/
public boolean isForceResponseEncoding() {
return this.forceResponseEncoding;
}
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String encoding = getEncoding();
if (encoding != null) {
if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
if (isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
filterChain.doFilter(request, response);
}
}
其中就有使用编码属性构造对象的构造方法,所以我们可以利用此初始化的时候直接传encoding值为UTF-8的属性给这个构造方法。接下来配置web.xml在原来基础上加入以下代码:
<!--配置过滤器,解决前端中文传输到后端乱码问题-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
完整的web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--springmvc核心配置器,前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置servlet启动时加载对象 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置过滤器,解决前端中文传输到后端乱码问题-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
运行项目,访问:http://localhost:8080/springmvc_day01_01_start_war/params.jsp
这就不乱码啦!!!
前端传参封装成集合对象
接下来就集合封装的使用方法啦分别是List和Map,给Account类添加集合属性的User泛型属性。
package com.tho.domain;
import java.util.List;
import java.util.Map;
public class Account {
private String username;
private String password;
private String money;
//封装一个对象
//private User user;
//封装集合对象
private List<User> list;
private Map<String,User> map;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMoney() {
return money;
}
public void setMoney(String money) {
this.money = money;
}
public List<User> getList() {
return list;
}
public void setList(List<User> list) {
this.list = list;
}
public Map<String, User> getMap() {
return map;
}
public void setMap(Map<String, User> map) {
this.map = map;
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", money='" + money + '\'' +
", list=" + list +
", map=" + map +
'}';
}
}
修改params.jsp
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/14
Time: 15:53
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- <a href="params/saveAccount">get请求</a>
//封装对象
<form action="params/saveAccount" method="post">
用户名称:<input type="text" name="username"><br/>
用户密码:<input type="password" name="password"><br/>
用户金额:<input type="text" name="money"><br/>
用户姓名:<input type="text" name="user.uname"><br/>
用户年龄:<input type="text" name="user.age"><br/>
<input type="submit" value="保存账户,post 请求">
</form>--%>
<form action="params/saveAccount" method="post">
用户名称:<input type="text" name="username"><br/>
用户密码:<input type="password" name="password"><br/>
用户金额:<input type="text" name="money"><br/>
<%--封装到list中--%>
用户姓名:<input type="text" name="list[0].uname"><br/>
用户年龄:<input type="text" name="list[0].age"><br/>
<%--封装到map中--%>
用户姓名:<input type="text" name="map['one'].uname"><br/>
用户年龄:<input type="text" name="map['one'].age"><br/>
<input type="submit" value="保存账户,post 请求">
</form>
</body>
</html>
修改paramController类的以下方法
@RequestMapping(value = "/saveAccount", method = RequestMethod.POST)
public String saveAccount(Account account) {
System.out.println("保存了账户");
System.out.println(account);
//System.out.println(account.getUser());
System.out.println(account.getList().toString());
System.out.println(account.getMap().toString());
return "success";
}
完整代码:
package com.tho.controller;
import com.tho.domain.Account;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("params")
public class ParamController {
//可以作用于类或者方法上都可以,path,和value作用相同都是映射路径注解,请求能有写多种请求方式
//传递可以传参数,也可以传对象等
@RequestMapping(value = "testparams", method = RequestMethod.GET)
public String testParam(String username) {
System.out.println("@RequestMapping起作用了");
System.out.println("用户名:" + username);
return "success";
}
/**
* 把用户封装到javaBean的类当中
*
* @return
*/
@RequestMapping(value = "/saveAccount", method = RequestMethod.POST)
public String saveAccount(Account account) {
System.out.println("保存了账户");
System.out.println(account);
//System.out.println(account.getUser());
System.out.println(account.getList().toString());
System.out.println(account.getMap().toString());
return "success";
}
}
启动项目:访问http://localhost:8080/springmvc_day01_01_start_war/params.jsp
前端写法list中括号索引值,map中括号键的名称,然后再点属性
我们提交的是文本类型和密码,但是都被正常写入,其实就是有springmvc帮我们进行了处理!!使用了它写好的类型转换器:
基本类型参数:
包括基本类型和 String 类型
POJO 类型参数:
包括实体类,以及关联的实体类
数组和集合类型参数:
包括 List 结构和 Map 结构的集合(包括数组)
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。
使用要求:
如果是基本类型或者 String 类型:
要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是 POJO 类型,或者它的关联对象:
要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
如果是集合类型,有两种方式:
```java
第一种:
要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。
给 List 集合中的元素赋值,使用下标。
给 Map 集合中的元素赋值,使用键值对。
第二种:
接收的请求参数是 json 格式数据。需要借助一个注解实现。
注意:
它还可以实现一些数据类型自动转换。内置转换器全都在:
org.springframework.core.convert.support 包下。有:
java.lang.Boolean -> java.lang.String : ObjectToStringConverter
java.lang.Character -> java.lang.Number : CharacterToNumberFactory
java.lang.Character -> java.lang.String : ObjectToStringConverter
java.lang.Enum -> java.lang.String : EnumToStringConverter
java.lang.Number -> java.lang.Character : NumberToCharacterConverter
java.lang.Number -> java.lang.Number : NumberToNumberConverterFactory
java.lang.Number -> java.lang.String : ObjectToStringConverter
java.lang.String -> java.lang.Boolean : StringToBooleanConverter
java.lang.String -> java.lang.Character : StringToCharacterConverter
java.lang.String -> java.lang.Enum : StringToEnumConverterFactory
java.lang.String -> java.lang.Number : StringToNumberConverterFactory
java.lang.String -> java.util.Locale : StringToLocaleConverter
java.lang.String -> java.util.Properties : StringToPropertiesConverter
java.lang.String -> java.util.UUID : StringToUUIDConverter
java.util.Locale -> java.lang.String : ObjectToStringConverter
java.util.Properties -> java.lang.String : PropertiesToStringConverter
java.util.UUID -> java.lang.String : ObjectToStringConverter
......
如遇特殊类型转换要求,需要我们自己编写自定义类型转换器
如2020-10-14这种类型转日期格式
自定义类型转换器
格式xxxx/xx/xx是可以识别的,可以自动转为Date类型,而xxxx-xx-xx是不行的需求自定义转换。
修改User类加上Date属性,同时给ParamsController添加saveUser方法以及修改params.jsp:
package com.tho.domain;
import java.util.Date;
public class User {
private String uname;
private Integer age;
private Date date;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", age=" + age +
", date=" + date +
'}';
}
}
package com.tho.controller;
import com.tho.domain.Account;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("params")
public class ParamController {
//可以作用于类或者方法上都可以,path,和value作用相同都是映射路径注解,请求能有写多种请求方式
//传递可以传参数,也可以传对象等
@RequestMapping(value = "testparams", method = RequestMethod.GET)
public String testParam(String username) {
System.out.println("@RequestMapping起作用了");
System.out.println("用户名:" + username);
return "success";
}
/**
* 把用户封装到javaBean的类当中
*
* @return
*/
@RequestMapping(value = "/saveAccount", method = RequestMethod.POST)
public String saveAccount(Account account) {
System.out.println("保存了账户");
System.out.println(account);
//System.out.println(account.getUser());
System.out.println(account.getList().toString());
System.out.println(account.getMap().toString());
return "success";
}
/*
自定义类型转换器
*/
@RequestMapping(value = "/saveUser", method = RequestMethod.POST)
public String saveUser(User user) {
System.out.println("保存了用户");
System.out.println(user);
return "success";
}
}
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/14
Time: 15:53
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- <a href="params/saveAccount">get请求</a>
//封装对象
<form action="params/saveAccount" method="post">
用户名称:<input type="text" name="username"><br/>
用户密码:<input type="password" name="password"><br/>
用户金额:<input type="text" name="money"><br/>
用户姓名:<input type="text" name="user.uname"><br/>
用户年龄:<input type="text" name="user.age"><br/>
<input type="submit" value="保存账户,post 请求">
</form>--%>
<%--
<form action="params/saveAccount" method="post">
用户名称:<input type="text" name="username"><br/>
用户密码:<input type="password" name="password"><br/>
用户金额:<input type="text" name="money"><br/>
<%–封装到list中–%>
用户姓名:<input type="text" name="list[0].uname"><br/>
用户年龄:<input type="text" name="list[0].age"><br/>
<%–封装到map中–%>
用户姓名:<input type="text" name="map['one'].uname"><br/>
用户年龄:<input type="text" name="map['one'].age"><br/>
<input type="submit" value="保存账户,post 请求">
</form>
--%>
<form action="params/saveUser" method="post">
用户姓名:<input type="text" name="uname"><br/>
用户年龄:<input type="text" name="age"><br/>
用户生日:<input type="text" name="date"><br/>
<input type="submit" value="保存用户,post 请求">
</form>
</body>
</html>
启动项目:访问http://localhost:8080/springmvc_day01_01_start_war/params.jsp
而使用xxxx-xx-xx尝试:
400错误坏的请求:由于被认为是客户端错误(例如,格式错误的请求语法、无效的请求消息框架或欺骗性的请求路由),服务器无法或不会处理请求
控制台也并没有tom对象生成。
解决方案给springmvc注入我们自定义的类型转换器!!
要成为类型转换器就必须实现Converter<S, T>接口
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.convert.converter;
import org.springframework.lang.Nullable;
/**
* A converter converts a source object of type {@code S} to a target of type {@code T}.
*
* <p>Implementations of this interface are thread-safe and can be shared.
*
* <p>Implementations may additionally implement {@link ConditionalConverter}.
*
* @author Keith Donald
* @since 3.0
* @param <S> the source type
* @param <T> the target type
*/
@FunctionalInterface
public interface Converter<S, T> {
/**
* Convert the source object of type {@code S} to target type {@code T}.
* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
* @return the converted object, which must be an instance of {@code T} (potentially {@code null})
* @throws IllegalArgumentException if the source cannot be converted to the desired target type
*/
@Nullable
T convert(S source);
}
1.现在com.tho下创建utils的包,再创建一个StringToDateConverter类实现 Converter<String, Date>
package com.tho.utils;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
把字符串转换城日期的类型转换器
*/
public class StringToDateConverter implements Converter<String, Date>{
/*
String source传进来的字符串
*/
@Override
public Date convert(String source) {
if (source==null){
throw new RuntimeException("请您输入日期");
}
DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
try{
return dateFormat.parse(source);//需要被try,catch
}catch (Exception e){
throw new RuntimeException("数据转换出错");
}
}
}
springmvc.xml加上配置的自定义转换器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置spring创建容器时要扫描的包 -->
<!-- 配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="com.tho"/>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 配置类型转换器工厂 -->
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 给工厂注入一个新的类型转换器 -->
<property name="converters">
<array>
<!-- 配置自定义类型转换器 -->
<bean class="com.tho.utils.StringToDateConverter"/>
</array>
</property>
</bean>
<!--配置spring开启注解mvc的支持,开启转换器组件支持-->
<mvc:annotation-driven conversion-service="converterService"/>
</beans>
启动项目:访问http://localhost:8080/springmvc_day01_01_start_war/params.jsp
访问servlet原生API
修改代码加入testServlet方法,完整代码如下:
package com.tho.controller;
import com.tho.domain.Account;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("params")
public class ParamController {
//可以作用于类或者方法上都可以,path,和value作用相同都是映射路径注解,请求能有写多种请求方式
//传递可以传参数,也可以传对象等
@RequestMapping(value = "testparams", method = RequestMethod.GET)
public String testParam(String username) {
System.out.println("@RequestMapping起作用了");
System.out.println("用户名:" + username);
return "success";
}
/**
* 把用户封装到javaBean的类当中
*
* @return
*/
@RequestMapping(value = "/saveAccount", method = RequestMethod.POST)
public String saveAccount(Account account) {
System.out.println("保存了账户");
System.out.println(account);
//System.out.println(account.getUser());
System.out.println(account.getList().toString());
System.out.println(account.getMap().toString());
return "success";
}
/*
自定义类型转换器
*/
@RequestMapping(value = "/saveUser", method = RequestMethod.POST)
public String saveUser(User user) {
System.out.println("保存了用户");
System.out.println(user);
return "success";
}
/*
访问servlet原生API
*/
@RequestMapping(value = "/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response) {
System.out.println("方法执行了。。");
System.out.println(request);
HttpSession session = request.getSession();
System.out.println(session);
ServletContext servletContext = session.getServletContext();
System.out.println(servletContext);
System.out.println(response);
return "success";
}
}
再indx.js配置一个超链接:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="hello">入门案例</a><br>
<a href="params/testparams?password=123">测试RequestMapping相关案例</a><br>
<a href="params//testServlet">Servlet原生API</a><br>
</body>
</html>
常用重点注解
使用RequestParam参数绑定
@RequestParam
用于获得请求参数
作用:
把请求中指定名称的参数给控制器中的形参赋值。
属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
案例:
在web-app根目录创建ann.jsp,com.tho.controller包下创建AnnoController类,他们的代码如下:
package com.tho.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
}
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/15
Time: 0:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="anno/testRequestMapping?name=张三">RequestMapping</a><br>
</body>
</html>
启动项目,完成后访问http://localhost:8080/springmvc_day01_01_start_war/anno.jsp
打印出执行了…和张三,证明绑定成功,需要注意的是前端传的参数属性必须和注解里绑定的值一致否则又是报400不好的请求。
@RequestBody
作用:
用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。
get 请求方式不适用。get的请求是参数是在url上的,而post的请求则是在报文里的请求体
属性:
required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值
为 false,get 请求得到是 null。
案例需求前端编写表单提交,后端使用@RequestBody注解:
anno.jsp加入表单代码,完整的如下:
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/15
Time: 0:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="anno/testRequestMapping?name=张三">RequestMapping</a><br>
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username"><br/>
用户年龄:<input type="text" name="age"><br/>
<input type="submit" value="保存用户,post 请求">
</form>
</body>
</html>
AnnoController:
package com.tho.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
}
运行完成后,访问http://localhost:8080/springmvc_day01_01_start_war/anno.jsp,然后输入参数Post提交
查看控制台
@PathVaribale
作用:
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
即前端访问一级目录或者n级目录/占位符所需参数,即访问后端一级目录或者n级目录/ {占位参数}
修改anno.jsp以及annoController:
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/15
Time: 0:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="anno/testRequestMapping?name=张三">RequestMapping</a><br>
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username"><br/>
用户年龄:<input type="text" name="age"><br/>
<input type="submit" value="保存用户,post 请求">
</form>
<a href="anno/testPathVaribale/10">PathVaribale</a><br>
</body>
</html>
package com.tho.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
/*
PathVaribale占位符注解
*/
@GetMapping("/testPathVaribale/{sid}")
public String testPathVaribale(@PathVariable(name = "sid") String id){
System.out.println("执行了..");
System.out.println(id);
return "success";
}
}
运行访问anno.jsp,点击占位符链接
@PutMapping,@DeleteMapping
同样是rest风格使用,但是由于浏览器form表单只能使用Post或者是get请求,所以测试的话需要 HiddentHttpMethodFilter
,隐藏请求过滤器,通过发送post请求将隐藏域
<input type="hidden" name="_method" value="PUT">
,请求转换成对象,然后从而实现Put或者是Delete请求。
作用:
由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添
加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT
与 DELETE 请求。
使用方法:
第一步:在 web.xml 中配置该过滤器。
第二步:请求方式必须使用 post 请求。
第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。
源码解析:
1.配置web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--springmvc核心配置器,前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置servlet启动时加载对象 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置过滤器,解决前端中文传输到后端乱码问题-->
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置HiddentHttpMethodFilter过滤器,修改浏览器请求为指定方式 -->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2.编写anno.jsp表单提交使用post方法,并使用隐藏域:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="anno/testRequestMapping?name=张三">RequestMapping</a><br>
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username"><br/>
用户年龄:<input type="text" name="age"><br/>
<input type="submit" value="保存用户,post 请求">
</form>
<a href="anno/testPathVaribale/10">PathVaribale</a><br>
<!-- 更新 -->
<form action="anno/testPutMapping/10" method="post">
更新用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="更新">
</form>
<!-- 删除 -->
<form action="anno/testDeleteMapping/10" method="post">
删除用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="删除">
</body>
</html>
3.编写AnnoController中put和delete方法:
package com.tho.controller;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
/*
PathVaribale占位符注解
*/
@GetMapping("/testPathVaribale/{sid}")
public String testPathVaribale(@PathVariable(name = "sid") String id){
System.out.println("执行了..");
System.out.println(id);
return "success";
}
/*
PutMapping注解
*/
@PutMapping("/testPutMapping/{sid}")
public String testPutMapping(@PathVariable(name = "sid") String id,User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("put了:"+user);
return "success";
}
/*
DeleteMapping注解
*/
@DeleteMapping("/testDeleteMapping/{sid}")
public String testDeleteMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("delete了"+user);
return "success";
}
}
运行,访问anno.jsp页面提交表单测试
浏览器无法处理这些请求,但是数据确实传到后台了
@RequestHeader
作用:
用于获取请求消息头。
属性:
value:提供消息头名称
required:是否必须有此消息头
在常用注解里属于用的比较少的
anno.jsp中加入超链接
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/15
Time: 0:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="anno/testRequestMapping?name=张三">RequestMapping</a><br>
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username"><br/>
用户年龄:<input type="text" name="age"><br/>
<input type="submit" value="保存用户,post 请求">
</form>
<a href="anno/testPathVaribale/10">PathVaribale</a><br>
<!-- 更新 -->
<form action="anno/testPutMapping/10" method="post">
更新用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="更新">
</form>
<!-- 删除 -->
<form action="anno/testDeleteMapping/10" method="post">
删除用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="删除">
</form>
<a href="anno/testRequestHeader">PathVaribale</a><br>
</body>
</html>
package com.tho.controller;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
/*
PathVaribale占位符注解
*/
@GetMapping("/testPathVaribale/{sid}")
public String testPathVaribale(@PathVariable(name = "sid") String id){
System.out.println("执行了..");
System.out.println(id);
return "success";
}
/*
PutMapping注解
*/
@PutMapping("/testPutMapping/{sid}")
public String testPutMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("put了:"+user);
return "success";
}
/*
DeleteMapping注解
*/
@DeleteMapping("/testDeleteMapping/{sid}")
public String testDeleteMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("delete了"+user);
return "success";
}
/*
获取请求头@RequestHeader,不指定就获取整个,指定就拿对应的
*/
@RequestMapping("testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
System.out.println("执行了..");
System.out.println(header);
return "success";
}
}
跑起来老规矩访问anno.jsp
@CookieValue
作用:
用于把指定 cookie 名称的值传入控制器方法参数。
属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie。
测试CookieValue超链接
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/15
Time: 0:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="anno/testRequestMapping?name=张三">RequestMapping</a><br>
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username"><br/>
用户年龄:<input type="text" name="age"><br/>
<input type="submit" value="保存用户,post 请求">
</form>
<a href="anno/testPathVaribale/10">PathVaribale</a><br>
<!-- 更新 -->
<form action="anno/testPutMapping/10" method="post">
更新用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="更新">
</form>
<!-- 删除 -->
<form action="anno/testDeleteMapping/10" method="post">
删除用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="删除">
</form>
<a href="anno/testRequestHeader">PathVaribale</a><br>
<a href="anno/testCookieValue">CookieValue</a><br>
</body>
</html>
AnnoController加入测试注解方法
package com.tho.controller;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
/*
PathVaribale占位符注解
*/
@GetMapping("/testPathVaribale/{sid}")
public String testPathVaribale(@PathVariable(name = "sid") String id){
System.out.println("执行了..");
System.out.println(id);
return "success";
}
/*
PutMapping注解
*/
@PutMapping("/testPutMapping/{sid}")
public String testPutMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("put了:"+user);
return "success";
}
/*
DeleteMapping注解
*/
@DeleteMapping("/testDeleteMapping/{sid}")
public String testDeleteMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("delete了"+user);
return "success";
}
/*
获取请求头@RequestHeader,不指定就获取整个,指定就拿对应的
*/
@RequestMapping("testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
System.out.println("执行了..");
System.out.println(header);
return "success";
}
/*
获取cookie
*/
@RequestMapping("testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){
System.out.println("执行了..");
System.out.println("JSESSIONID: "+cookieValue);
return "success";
}
}
访问anno.jsp:
@ModelAttribute
作用:
该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。
<%--
Created by IntelliJ IDEA.
User: HaSee
Date: 2020/10/15
Time: 0:40
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="anno/testRequestMapping?name=张三">RequestMapping</a><br>
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username"><br/>
用户年龄:<input type="text" name="age"><br/>
<input type="submit" value="保存用户,post 请求">
</form>
<a href="anno/testPathVaribale/10">PathVaribale</a><br>
<!-- 更新 -->
<form action="anno/testPutMapping/10" method="post">
更新用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="PUT"/>
<input type="submit" value="更新">
</form>
<!-- 删除 -->
<form action="anno/testDeleteMapping/10" method="post">
删除用户:<input type="text" name="uname"><br/>
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="删除">
</form>
<a href="anno/testRequestHeader">PathVaribale</a><br>
<a href="anno/testCookieValue">CookieValue</a><br>
<form action="anno/testModelAttribute" method="post">
用户姓名:<input type="text" name="uname"><br/>
用户年龄:<input type="text" name="age"><br/>
<input type="submit" value="提交测试ModelAttribute">
</form>
</body>
</html>
package com.tho.controller;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
/*
PathVaribale占位符注解
*/
@GetMapping("/testPathVaribale/{sid}")
public String testPathVaribale(@PathVariable(name = "sid") String id){
System.out.println("执行了..");
System.out.println(id);
return "success";
}
/*
PutMapping注解
*/
@PutMapping("/testPutMapping/{sid}")
public String testPutMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("put了:"+user);
return "success";
}
/*
DeleteMapping注解
*/
@DeleteMapping("/testDeleteMapping/{sid}")
public String testDeleteMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("delete了"+user);
return "success";
}
/*
获取请求头@RequestHeader,不指定就获取整个,指定就拿对应的
*/
@RequestMapping("testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
System.out.println("执行了..");
System.out.println(header);
return "success";
}
/*
获取cookie
*/
@RequestMapping("testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){
System.out.println("执行了..");
System.out.println("JSESSIONID: "+cookieValue);
return "success";
}
/*
ModelAttribute方法,可在方法以及参数上使用
*/
@RequestMapping("testModelAttribute")
public String testModelAttribute(){
System.out.println("执行了testModelAttribut..");
return "success";
}
@ModelAttribute
public void showUser(){
System.out.println("showUser..+我加了 @ModelAttribute在类上,我先执行");
}
}
运行:
演示ModelAttribute作用
由于有时候表单提交,提交的值不是都是和属性完全对应,那么如果不提前处理就会出现没比较的值为空覆盖了数据库里的值!所以可以先处理,拿到旧值再执行提交
修改annoController控制器方法:
package com.tho.controller;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
/*
PathVaribale占位符注解
*/
@GetMapping("/testPathVaribale/{sid}")
public String testPathVaribale(@PathVariable(name = "sid") String id){
System.out.println("执行了..");
System.out.println(id);
return "success";
}
/*
PutMapping注解
*/
@PutMapping("/testPutMapping/{sid}")
public String testPutMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("put了:"+user);
return "success";
}
/*
DeleteMapping注解
*/
@DeleteMapping("/testDeleteMapping/{sid}")
public String testDeleteMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("delete了"+user);
return "success";
}
/*
获取请求头@RequestHeader,不指定就获取整个,指定就拿对应的
*/
@RequestMapping("testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
System.out.println("执行了..");
System.out.println(header);
return "success";
}
/*
获取cookie
*/
@RequestMapping("testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){
System.out.println("执行了..");
System.out.println("JSESSIONID: "+cookieValue);
return "success";
}
/*
ModelAttribute方法,可在方法以及参数上使用
*/
@RequestMapping("testModelAttribute")
public String testModelAttribute(User user){
System.out.println("执行了testModelAttribut..");
System.out.println(user);
return "success";
}
@ModelAttribute
public User showUser(String uname){
System.out.println("showUser..+我加了 @ModelAttribute在类上,我先执行");
User user=new User();
user.setUname("zhangsan");
user.setAge(20);
user.setDate(new Date());
return user;
}
}
这样旧数据有的,会被拿的数据会被覆盖,而没有操作的数据则不会被置为Null
另一种使用在参数上则是结合Map集合使用,先将就的对象封装成Map,同样是两个方法,先处理取值的方法在方法上使用@ModelAttribute,而后取的方法则是在参数@ModelAttribute去值,注解修饰的参数必须要和Map的键对应
!!
package com.tho.controller;
import com.tho.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.Map;
/*
常用注解
*/
@Controller
@RequestMapping("/anno")//放在类上作用相当于路由
public class AnnoController {
//即使属性名和前端参数属性一致,但没加注解的话,实际上没有绑定起来需要使用@RequestParam("和前端参数一致")
@GetMapping("/testRequestMapping")
public String testRequestMapping(@RequestParam("name") String username){
System.out.println("执行了..");
System.out.println(username);
return "success";
}
/*
获取到请求体的内容
*/
@PostMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了..");
System.out.println(body);
return "success";
}
/*
PathVaribale占位符注解
*/
@GetMapping("/testPathVaribale/{sid}")
public String testPathVaribale(@PathVariable(name = "sid") String id){
System.out.println("执行了..");
System.out.println(id);
return "success";
}
/*
PutMapping注解
*/
@PutMapping("/testPutMapping/{sid}")
public String testPutMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("put了:"+user);
return "success";
}
/*
DeleteMapping注解
*/
@DeleteMapping("/testDeleteMapping/{sid}")
public String testDeleteMapping(@PathVariable(name = "sid") String id, User user){
System.out.println("执行了..");
System.out.println(id);
System.out.println("delete了"+user);
return "success";
}
/*
获取请求头@RequestHeader,不指定就获取整个,指定就拿对应的
*/
@RequestMapping("testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept") String header){
System.out.println("执行了..");
System.out.println(header);
return "success";
}
/*
获取cookie
*/
@RequestMapping("testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookieValue){
System.out.println("执行了..");
System.out.println("JSESSIONID: "+cookieValue);
return "success";
}
/*
ModelAttribute方法,可在方法以及参数上使用
*/
@RequestMapping("testModelAttribute")
public String testModelAttribute(@ModelAttribute(value = "userMap") User user){
System.out.println("执行了testModelAttribut..");
System.out.println(user);
return "success";
}
// @ModelAttribute
// public User showUser(String uname){
// System.out.println("showUser..+我加了 @ModelAttribute在类上,我先执行");
// User user=new User();
// user.setUname("zhangsan");
// user.setAge(20);
// user.setDate(new Date());
// return user;
// }
@ModelAttribute
public void showUser(Map<String,User> map){
System.out.println("showUser..+我加了 @ModelAttribute在类上,我先执行");
User user=new User();
user.setUname("zhangsan");
user.setAge(20);
user.setDate(new Date());
map.put("userMap",user);
}
}
重新运行
@SessionAttributes
作用:
用于多次执行控制器方法间的参数共享。
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型。
只能作用于类上面
anno.jsp加一行超链接
<a href="anno/testSessionAttributes">testSessionAttributes</a><br>
AnnoController类上加上注解以及其属性值以及加上测试注解的方法:
@SessionAttributes(value={"msg"},types = {String.class})
@RequestMapping(value = "/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("testSessionAttributes...");
//底层会存储到request域对象中
model.addAttribute("msg","消息");
return "success";
}
修改success.jsp通过域对象取值:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功!!</h3>
${msg}<br>
${sessionScope}
</body>
</html>
运行访问anno.jsp:
点击测试
至此以及将msg属性参数等于消息存到session域了
接下来测试在session域获得值
anno.jsp加入超链接测试取值:
<a href="anno/testGetAttributes">testGetAttributes</a><br>
编写后端AnnoController取值代码:
/*
从session域里面取值
*/
@RequestMapping(value = "/testGetAttributes")
public String testGetAttributes(ModelMap modelMap){
System.out.println("testGetAttributes...");
//使用Map的实现类modelMap获取已经在session域里的值
String msgStr =(String) modelMap.get("msg");
System.out.println(msgStr);
return "success";
}
运行访问anno.jsp:
正常应该先存值再取值:直接取值会返回一个{},即为空的意思
看控制台输出null开始即明白,一开始获取的时候是还没存,所以会有null
当然我们也可以删除session里面存储的参数对象!!
接下来编写:anno.jsp,加入清除链接
<a href="anno/testDeleteAttributes">testDeleteAttributes</a><br>
AnnoController类加入方法:
/*
清除session存入参数对象
*/
@RequestMapping("testDeleteAttributes")
public String testDeleteAttributes(SessionStatus status){
System.out.println("testDeleteAttributes..");
status.setComplete();
return "success";
}
运行访问:访问anno.jsp,然后测试操作步骤为:点击设参数链接,返回再点击取参数链接,再返回点击清除参数链接,最后点一次取参数链接!然后查看控制台。
最后取值为空:
控制台可以测试成功!
同时可总结,@SessionAttributes执行优先于所有方法注解,而方法注解则是@ModelAttribute的执行最早!!
到此本文的内容暂时到此,下篇文章会更新与响应有关的内容以及其常用注解!
代码托管在gitee,地址为:https://gitee.com/calmtho/springmvcdemo