SpringMVC常用注解(三)
一、@Controller 、@RestController 和 @ControllerAdvice
1. @Controller
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。
使用@Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面;
若返回json等内容到页面,则需要加@ResponseBody注解。
2. @RestController
@RestController注解相当于@ResponseBody + @Controller合在一起的作用。
返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面,返回的内容就是return 里的内容。
若使用@RestController,又想返回页面,则需要使用ModelAndView:
public ModelAndView login(){ ModelAndView mv = new ModelAndView("index"); return mv; }
3. @ControllerAdvice
@ControllerAdvice,是Spring3.2后提供的新注解,从名字上可以看出大体意思是控制器增强。
ControllerAdvice拆分开来就是Controller Advice,关于Advice,其是用于封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ContrllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行“切面”环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的(@ControllerAdvice并不是使用AOP的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持)。@ControllerAdvice是在类上声明的注解,其用法主要有三点:
(1) 全局异常处理,结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的
@ControllerAdvice(basePackages = "mvc") public class SpringControllerAdvice { @ExceptionHandler(RuntimeException.class) public ModelAndView runtimeException(RuntimeException e) { e.printStackTrace(); return new ModelAndView("error"); } }
在该接口中抛出了RuntimeException,那么理论上,这里的异常捕获器就会捕获该异常,然后返回默认的error视图。以下是UserController的代码:
@RequestMapping(value = "/detail", method = RequestMethod.GET) public ModelAndView detail(@RequestParam("id") long id) { ModelAndView view = new ModelAndView("user"); User user = userService.detail(id); view.addObject("user", user); throw new RuntimeException("mock user detail exception."); }
在UserController中抛出的异常能够被SpringControllerAdvice捕获。
这里需要注意的是,统一处理异常的controller需要放在和普通controller同级的包下,或者在ComponentScan的包下。在处理异常的时候可以使用System.out的方式,也可以使用logger.info,或者可以入到数据库中。
(2) 全局数据绑定,结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的;
对于@InitBinder,该注解的主要作用是绑定一些自定义的参数。一般情况下我们使用的参数通过@RequestParam,@RequestBody或者@ModelAttribute等注解就可以进行绑定了,但对于一些特殊类型参数,比如Date,它们的绑定Spring是没有提供直接的支持的,我们只能为其声明一个转换器,将request中字符串类型的参数通过转换器转换为Date类型的参数,从而供给@RequestMapping标注的方法使用。
@ControllerAdvice(basePackages = "mvc") public class SpringControllerAdvice { @InitBinder public void globalInitBinder(WebDataBinder binder) { binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); } }
@InitBinder标注的方法注册的Formatter在每次request请求进行参数转换时都会调用,用于判断指定的参数是否为其可以转换的参数。以下是UserController的代码:
@RequestMapping(value = "/detail", method = RequestMethod.GET) public ModelAndView detail(@RequestParam("id") long id, Date date) { System.out.println(date); ModelAndView view = new ModelAndView("user"); User user = userService.detail(id); view.addObject("user", user); return view; }
(3) 全局数据预处理,结合方法型注解@ModelAttribute,表示其标注的方法将会在目标Controller方法执行之前执行。
使用@ModelAttribute,如果声明在方法上,并且结合@ControllerAdvice,该方法将会在@ControllerAdvice所指定的范围内的所有接口方法执行之前执行,并且@ModelAttribute标注的方法的返回值还可以供给后续会调用的接口方法使用。
@ControllerAdvice(basePackages = "mvc") public class SpringControllerAdvice { @ModelAttribute(value = "message") public String globalModelAttribute() { System.out.println("global model attribute."); return "this is from model attribute"; } }
这里需要注意的是,该方法提供了一个String类型的返回值,而@ModelAttribute中指定了该属性名称为message,这样在Controller层就可以接收该参数了,如下是UserController(普通的@Controller):
@RequestMapping(value = "/detail", method = RequestMethod.GET) public ModelAndView detail(@RequestParam("id") long id, @ModelAttribute("message") String message) { System.out.println(message); ModelAndView view = new ModelAndView("user"); User user = userService.detail(id); view.addObject("user", user); return view; }
@ModelAttribute标注的方法的执行是在所有拦截器的preHandle()方法执行之后才会执行。
4. @ControllerAdvice和@RestControllerAdvice的区别
//@ControllerAdvice和@RestControllerAdvice都可以指向控制器的一个子集 // 指向所有带有注解@RestController的控制器 @ControllerAdvice(annotations = RestController.class) public class AnnotationAdvice {}
// 指向所有指定包中的控制器 @ControllerAdvice("org.example.controllers") public class BasePackageAdvice {}
// 指向所有带有指定签名的控制器 @ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class}) public class AssignableTypesAdvice {}
@ControllerAdvice和@RestControllerAdvice的区别 类似于 @RestController 与 @Controller的区别。
二、@RequestBody 和 @ResponseBody
1. @RequestBody
@RequestBody是作用在形参列表上,用于将前台发送过来固定格式的数据【xml 格式或者 json等】封装为对应的 JavaBean 对象,封装时使用到的一个对象是系统默认配置的 HttpMessageConverter进行解析,然后封装到形参上。
public Object login(@RequestBody User loginUuser, HttpSession session)
2. @ResponseBody
@ResponseBody是作用在方法上的,@ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用【也就是AJAX】,在使用 @RequestMapping后,返回值通常解析为跳转路径,但是加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中。 比如异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据。@RequestBody 将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象。
@ResponseBody public Object login(String name, String password, HttpSession session)
三、@ModelAttribute 和 @SessionAttributes
1. @ModelAttribute
@ModelAttribute注释方法,被@ModelAttribute注释的方法会在此controller每个方法执行前被执行,因此对于一个controller映射多个URL的用法来说,要谨慎使用。
(1) @ModelAttribute注释void返回值的方法
@Controller public class HelloWorldController { @ModelAttribute public void populateModel(@RequestParam String abc, Model model) { model.addAttribute("attributeName", abc); } @RequestMapping(value = "/helloWorld") public String helloWorld() { return "helloWorld"; } }
(2) @ModelAttribute注释返回具体类的方法
@ModelAttribute public Account addAccount(@RequestParam String number) { return accountManager.findAccount(number); }
这种情况,model属性的名称没有指定,它由返回类型隐含表示,如这个方法返回Account类型,那么这个model属性的名称是account。
这个例子中model属性名称由返回对象类型隐含表示,model属性对象就是方法的返回值。它无须要特定的参数。
(3) @ModelAttribute(value="")注释返回具体类的方法
@Controller public class HelloWorldController { @ModelAttribute("attributeName") public String addAccount(@RequestParam String abc) { return abc; } @RequestMapping(value = "/helloWorld") public String helloWorld() { return "helloWorld"; } }
这个例子中使用@ModelAttribute注释的value属性,来指定model属性的名称。model属性对象就是方法的返回值。它无须要特定的参数。
(4) @ModelAttribute和@RequestMapping同时注释一个方法
@Controller public class HelloWorldController { @RequestMapping(value = "/helloWorld.do") @ModelAttribute("attributeName") public String helloWorld() { return "hi"; } }
这时这个方法的返回值并不是表示一个视图名称,而是model属性的值,视图名称由RequestToViewNameTranslator根据请求"/helloWorld.do"转换为逻辑视图helloWorld。
Model属性名称由@ModelAttribute(value=””)指定,相当于在request中封装了key=attributeName,value=hi。
@ModelAttribute注释一个方法的参数
(1) 从model中获取
@Controller public class HelloWorldController { @ModelAttribute("user") public User addAccount() { return new User("jz","123"); } @RequestMapping(value = "/helloWorld") public String helloWorld(@ModelAttribute("user") User user) { user.setUserName("jizhou"); return "helloWorld"; } }
在这个例子里,@ModelAttribute("user") User user注释方法参数,参数user的值来源于addAccount()方法中的model属性。
此时如果方法体没有标注@SessionAttributes("user"),那么scope为request,如果标注了,那么scope为session。
(2) 从Form表单或URL参数中获取(实际上,不做此注释也能拿到user对象)
@Controller public class HelloWorldController { @RequestMapping(value = "/helloWorld") public String helloWorld(@ModelAttribute User user) { return "helloWorld"; } }
注意这时候这个User类一定要有没有参数的构造函数。
@ModelAttribute注解作用在方法上或者方法的参数上,表示将被注解的方法的返回值或者是被注解的参数作为Model的属性加入到Model中,然后Spring框架自会将这个Model传递给ViewResolver。Model的生命周期只有一个http请求的处理过程,请求处理完后,Model就销毁了。
如果想让参数在多个请求间共享,那么可以用到要说到的@SessionAttribute注解。
2. @SessionAttributes
@SessionAttributes作用于处理器类上,用于在多个请求之间传递参数,类似于Session的Attribute,但不完全一样,一般来说@SessionAttribute设置的参数只用于暂时的传递,而不是长期的保存,长期保存的数据还是要放到Session中。
通过@SessionAttributes注解设置的参数有3类用法:
- 在视图中通过request.getAttribute或session.getAttribute获取
- 在后面请求返回的视图中通过session.getAttribute或者从model中获取
- 自动将参数设置到后面请求所对应处理器的Model类型参数或者有@ModelAttribute注释的参数里面。
将一个参数设置到SessionAttribute中需要满足两个条件:
- 在@SessionAttribute注解中设置了参数的名字或者类型
- 在处理器中将参数设置到了model中。
@Controller @RequestMapping("sc") @SessionAttributes("name") public class SessionController { @RequestMapping("session") public String sessions(Model model,HttpSession session){ model.addAttribute("name", "winclpt"); session.setAttribute("myName", "chke"); return "session"; }
上面的代码将Model中的name参数保存到了session中(如果Model中没有name参数,而session中存在一个name参数,那么SessionAttribute会这个参数塞进Model中)
SessionAttributes有两个参数:
String[] value:要保存到session中的参数名称
Class[] typtes:要保存的参数的类型,和value中顺序要对应上
所以可以这样写:@SessionAttributes(types = {User.class,Dept.class},value={“attr1”,”attr2”})
原理理解:它的做法大概可以理解为将Model中的被注解的attrName属性保存在一个SessionAttributesHandler中,在每个RequestMapping的方法执行后,这个SessionAttributesHandler都会将它自己管理的“属性”从Model中写入到真正的HttpSession;同样,在每个RequestMapping的方法执行前,SessionAttributesHandler会将HttpSession中的被@SessionAttributes注解的属性写入到新的Model中。
如果想删除session中共享的参数,可以通过SessionStatus.setComplete(),这句只会删除通过@SessionAttributes保存到session中的参数
四、 @Autowired
首先要知道另一个东西,default-autowire,它是在xml文件中进行配置的,可以设置为byName、byType、constructor和autodetect;比如byName,不用显式的在bean中写出依赖的对象,它会自动的匹配其它bean中id名与本bean的set**相同的,并自动装载。
@Autowired是用在JavaBean中的注解,通过byType形式,用来给指定的字段或方法注入所需的外部资源。
- no:默认不使用autowiring。 必须显示的使用”“标签明确地指定bean。
- byName:根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。
- byType:如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置 dependency-check=”objects”让Spring抛出异常。
- constructor:与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
- autodetect:通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。
在属性中使用该注解,不用再写setXXX方法。
五、@Value、 @Required、@Validated
1. @Validated
@Valid是javax.validation里的。
@Validated是@Valid 的一次封装,是Spring提供的校验机制使用。@Valid不提供分组功能。
(1) 分组
当一个实体类需要多种验证方式时,例:对于一个实体类的id来说,新增的时候是不需要的,对于更新时是必须的。
可以通过groups对验证进行分组。
//分组接口类(通过向groups分配不同类的class对象,达到分组目的): public interface First { }
//在bean定义的时候: //在First分组时,判断不能为空 @NotEmpty(groups={First.class}) private String id;
//控制类: //不需验证ID public String addPeople(@Validated People p,BindingResult result) //验证ID public String updatePeople(@Validated({First.class}) People p,BindingResult result)
注意:
- 不分配groups,默认每次都要进行验证
-
对一个参数需要多种验证方式时,也可通过分配不同的组达到目的
(2) 组序列
默认情况下,不同组别的约束验证是无序的,然而在某些情况下,约束验证的顺序却很重要。
//分组接口类 public interface First { } public interface Second { }
//通过@GroupSequence注解对组进行排序 @GroupSequence({First.class,Second.class}) public interface Group { }
//验证ID public String addPeople(@Validated({Group.class}) People p,BindingResult result)
2. @Value
为了简化读取properties文件中的配置值,spring支持@value注解的方式来获取,这种方式大大简化了项目配置,提高业务中的灵活性。
两种使用方式:
- @Value("#{configProperties['key']}")
- @Value("${key}")
(1) @Value("#{configProperties['key']}")
配置方法一:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="locations"> <list> <value>classpath:value.properties</value> </list> </property> </bean>
配置方法二:
<util:properties id="configProperties" location="classpath:value.properties"></util:properties>
注:方法一和方法二是等价的,这种方法需要util标签,要引入util的xsd:
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd"
value.properties
key=1
ValueDemo.java
@Component
public class ValueDemo {
@Value("#{configProperties['key']}")
private String value;
public String getValue() {
return value;
}
}
(2) @Value("${key}")
<!--在上面的配置基础上加上:--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="properties" ref="configProperties"/> </bean> <!--或直接完整指定:--> <bean id="appProperty" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <array> <value>classpath:value.properties</value> </array> </property> </bean>
@Component public class ValueDemo { @Value("${key}") private String value; public String getValue() { return value; } }
3. @Required
@Required 注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。
<bean id="resultMessage" class="com.jake.ResultMessage"> <property name="code" value="001" /><!--设置属性--> </bean>
使用<context:annotation-config/>会隐式地注册RequiredAnnotationBeanPostProcessor,使@Required注解生效,如果没有就必须在xml文件中配置RequiredAnnotationBeanPostProcessor bean。
注意:@Required只能设置在setter方法上
六、@ExceptionHandler、@ResponseStatus
@ExceptionHandler只有一个参数,可以是一个数组,表示要捕获的异常。
@ResponseStatus
注解中有两个参数,value属性设置异常的状态码,reaseon是异常的描述。
状态码定义在HttpStatus上。
七、@RequestMapping
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@RequestMapping 除了修饰方法, 还可来修饰类 :
- 类定义处: 提供初步的请求映射信息。相对于 WEB 应用的根目录;
- 方法处: 提供进一步的细分映射信息。 相对于类定义处的 URL。
- 若类定义处未标注 @RequestMapping,则方法处标记的 URL相对于 WEB 应用的根目录
- 返回ModelAndView时的url会根据你的 @RequestMapping实际情况组成。
- 对应项目jsp位置则是一级路径对应一级文件目录:如url为/default/index对应项目中webapp/default/index.jsp
- 如果类上没有映射,那么url直接就是方法的映射;否则url为类上+方法上映射路径组合。
RequestMapping注解有六个属性,下面我们把它分成三类进行说明:
- value:指定请求的实际地址,指定的地址可以是URI Template 模式;
- method: 指定请求的method类型, GET、POST、PUT、DELETE等,在RequestMethod定义;
- consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
- produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
- params: 指定request中必须包含某些参数值时,才让该方法处理;
- headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求;
八、@InitBinder
从字面意思可以看出这个的作用是给Binder做初始化的,被此注解的方法可以对WebDataBinder初始化。WebDataBinder是用于表单到方法的数据绑定的!
@InitBinder只在@Controller中注解方法来为这个控制器注册一个绑定器初始化方法,方法只对本控制器有效。
1. 对数据绑定进行设置
WebDataBinder中有很多方法可以对数据绑定进行具体的设置:比如我们设置name属性为非绑定属性(也可以设置绑定值setAllowedFields):
@InitBinder public void initBinder(WebDataBinder binder) { //setDisallowedFields表示禁止接收的参数 binder.setDisallowedFields("name"); }
2. 注册已有的编辑器
WebDataBinder是用来绑定请求参数到指定的属性编辑器.由于前台传到controller里的值是String类型的,当往Model里Set这个值的时候,如果set的这个属性是个对象,Spring就会去找到对应的editor进行转换,然后再set进去!Spring自己提供了大量的实现类(在org.springframwork.beans.propertyEditors下的所有editor),诸如CustomDateEditor ,CustomBooleanEditor,CustomNumberEditor等许多,基本上够用。 在平时使用SpringMVC时,会碰到javabean中有Date类型参数,表单中传来代表日期的字符串转化为日期类型,SpringMVC默认不支持这种类型的转换。我们就需要手动设置时间格式并在webDateBinder上注册这个编辑器!
//这里我们在@RequestMapping参数上就可以直接使用Date类型的参数。 CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true); binder.registerCustomEditor(Date.class, editor);
3. 注册自定义编辑器
用自定义编辑器就是在第二个的基础上添加个自定义编辑器就行了,自定义的编辑器类需要继承org.springframework.beans.propertyeditors.PropertiesEditor;,并重写setAsText和getAsText两个方法就行了!
比如下面这个DoubleEditor:
public class DoubleEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.equals("")) { text = "0"; } setValue(Double.parseDouble(text)); } @Override public String getAsText() { return getValue().toString(); } }
4. 设置属性的前缀可以实现参数绑定
form表单:
<form action="/testBean" method="post"> name: <input type="text" name="u.name"> <br> age: <input type="text" name="u.age"> <br> name: <input type="text" name="s.name"> <br> age: <input type="text" name="s.age"> <br> <input type="submit"> </form>
Controller:
@InitBinder("user") public void init1(WebDataBinder binder) { binder.setFieldDefaultPrefix("u."); } @InitBinder("stu") public void init2(WebDataBinder binder) { binder.setFieldDefaultPrefix("s."); } @RequestMapping("/testBean") public ModelAndView testBean(User user, @ModelAttribute("stu") Student stu) { System.out.println(stu); System.out.println(user); String viewName = "success"; ModelAndView modelAndView = new ModelAndView(viewName); modelAndView.addObject("user", user); modelAndView.addObject("student", stu); return modelAndView; }
九、@PathVariable
@PathVariable 映射 URL 绑定的占位符:
- 带占位符的 URL 是 Spring3.0 新增的功能,该功能在SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义
- 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。
如:
<a href="springmvc/testPathVariable/1">testPathVariable</a>
//@PathVariable可以用来映射URL中的占位符到目标方法的参数中 @RequestMapping("/testPathVariable/{id}") public String testPathVariable(@PathVariable("id") Integer id){ System.out.println("testPathVariable:"+id); return SUCCESS; }
REST的支持
- /order/1 HTTP GET :得到 id = 1 的 order
- /order/1 HTTP DELETE:删除 id = 1的 order
- /order/1 HTTP PUT:更新id = 1的 order
- /order HTTP POST:新增 order
HiddenHttpMethodFilter:浏览器 form 表单只支持 GET与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与DELETE 请求。
<!-- 配置org.springframework.web.filter.HiddenHttpMethodFilter:可以把POST请求转换成DELETE或者POST请求 --> <filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
十、@RequestHeader、@RequestParam、@CookieValue
1. @RequestHeader
@RequestHeader 注解,可以把Request请求header部分的值绑定到方法的参数上。
这是一个Request 的header部分:
- Host localhost:8080
- Accept text/html,application/xhtml+xml,application/xml;q=0.9
- Accept-Language fr,en-gb;q=0.7,en;q=0.3
- Accept-Encoding gzip,deflate
- Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
- Keep-Alive 300
2. @RequestParam
在SpringMvc后台进行获取数据,一般是两种。
- request.getParameter(“参数名”)
- 用@RequestParam注解获取
@RequestParam 有三个属性:
(1) value:请求参数名(必须配置)
(2) required:是否必需,默认为 true,即 请求中必须包含该参数,如果没有包含,将会抛出异常(可选配置)
(3) defaultValue:默认值,如果设置了该值,required 将自动设为 false,无论你是否配置了required,配置了什么值,都是 false(可选配置)
值得注意的是:如果方法上的@RequestMapping 配置了 params 属性,则请求中也必须包含该参数。
//可以对传入参数指定参数名: // 下面的对传入参数指定为aa,如果前端不传aa参数名,会报错 @RequestParam(value="aa") String inputStr //可以通过required=false或者true来要求@RequestParam配置的前端参数是否一定要传 // required=false表示不传的话,会给参数赋值为null,required=true就是必须要有 @RequestMapping("testRequestParam") public String filesUpload(@RequestParam(value="aa", required=true) String inputStr, HttpServletRequest request) /**如果@requestParam注解的参数是int类型,并且required=false,此时如果不传参数的话,会报错。原因是,required=false时,不传参数的话,会给参数赋值null,这样就会把null赋值给了int,因此会报错。*/ // required=false表示不传的话,会给参数赋值为null,required=true就是必须要有 @RequestMapping("testRequestParam") public String filesUpload(@RequestParam(value="aa", required=false) int inputStr, HttpServletRequest request) //若是前端页面不传参的话,此处就会报错。当然可以用Integer代替int