@Resource注解的使用
@Resource注解的功能和@Autowired
将我们之前编写的代码中的@Autowired注解替换为@Resource一般情况下都是可以正常运行的
也就是说由@Resource标注的属性也会进行自动装配
他们的区别是:
1.提供者不同:@Autowired是Spring提供的@Resource是java提供的
2.注入规则不同:
原则上@Autowired注入规则为"byType"(通过类型)
@Resource注入规则为"byName"(通过名称)这里的名称就是对象的id
@Autowired是先检查类型,如果有类型匹配直接匹配,只通过类型不能匹配了,再通过id
@Resource是先匹配id,如果id匹配直接成功,如果没有id匹配再匹配类型
SpringMVC
什么是MVC
MVC实际上并不是Spring专有的
MVC实际是指
M:Model(数据模型) V:View(视图) C:Controller(控制器)
M:实体类 V:页面 C:Servlet
由于自己编写MVC思想的项目有些步骤比较繁琐所以市面上有很多MVC框架
简化MVC设计编写过程
常见的有:Struts2,JFinal,SpringMVC
SpringMvc概述
SpringMvc实际上主要针对的是视图(V)到控制器©的代码
控制器中要想获得视图的信息有很多冗余代码
(Servlet中需要很多request.getParameter()这样的方法获得表单中的信息)
如果使用SpringMvc就能简便的获得他们
而且现在我们是请求和Servlet1对1的关系,
如果项目大,请求多nameServlet的数量也是不可控的
这也是SpringMvc解决的问题
SpringMvc执行流程
- DispatcherServlet:前端控制器,用于接收所有请求
- HandlerMapping:用于配置请求与运行的方法的对应关系
- Controller:控制器,这种对象时我们编写处理具体功能的
- ModelAndView:控制器完成请求处理后,的处理结果一般是指定页面名称
- ViewResolver:视图解析器,根据给定的页面名称,生成页面内容
SpringMvc的HelloWorld程序
步骤1:
修改一下web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
步骤2:
添加pom.xml文件中 SpringMvc以及其他相关内容的依赖
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<!-- Thymeleaf整合Spring -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
步骤3:
创建一个包(cn.tedu.config)
在这个包新建一个WebApp类
代码如下
//AbstractAnnotationConfigDispatcherServletInitializer
//是SpringMVC提供的,它包含几个必须由我们重写并配置SpringMvc运行信息的方法
public class WebApp extends
AbstractAnnotationConfigDispatcherServletInitializer {
// 继承的这个抽象类有一个特征
// tomcat一旦启动就会自动运行下面的三个方法
@Override
protected Class<?>[] getRootConfigClasses() {
System.out.println("111111");
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
System.out.println("222222");
return new Class[0];
}
@Override
protected String[] getServletMappings() {
System.out.println("333333");
return new String[0];
}
}
启动tomcat会看到111,222,333的输出
证明现在SpringMvc框架配置是正确的
步骤4:
配置SpringMvc的信息
有两方面信息要配置
1.请求的拦截规则 我们暂时规定 以".do"结尾的请求由SpringMvc接收处理
2.指定Spring的配置类,配置的是配置类的反射
//AbstractAnnotationConfigDispatcherServletInitializer
//是SpringMVC提供的,它包含几个必须由我们重写并配置SpringMvc运行信息的方法
public class WebApp extends
AbstractAnnotationConfigDispatcherServletInitializer {
// 继承的这个抽象类有一个特征
// tomcat一旦启动就会自动运行下面的三个方法
//RootConfig配置和控制器无关的Spring配置类
@Override
protected Class<?>[] getRootConfigClasses() {
System.out.println("111111");
return new Class[0];
}
//ServletConfig配置和控制器相关的Spring配置类
@Override
protected Class<?>[] getServletConfigClasses() {
System.out.println("222222");
return new Class[]{SpringMvcConfig.class};
}
//getServletMappings是指定SpringMvc对什么样的请求进行处理的方法
//配置*.do 表示所有以.do结尾的请求,都会交由SpringMvc处理
@Override
protected String[] getServletMappings() {
System.out.println("333333");
return new String[]{"*.do"};
}
}
步骤5:
创建配置类
SpringMvcConfig类
只需要添加一个扫描的包就可以了
@ComponentScan("cn.tedu.controller")
public class SpringMvcConfig {
}
步骤6:
创建cn.tedu.controller包
在这个包中新建一个控制器DemoController
//使用@Controller注解这个类
//能够将这个类注入到Spring容器的同时还能表明它是一个控制器
@Controller
public class DemoController {
// 编写@GetMapping注解来规定什么请求能够访问这个方法
// 我们配置了只有.do结尾的请求能够进入SpringMvc所以这里的路径必须以.do结尾
@GetMapping("/hello.do")
// 我们由于没有具体页面可以显示,所以需要添加下面的注解
// 表示当前请求的结果就是在浏览器上显示返回的字符串
@ResponseBody
public String demo(){
System.out.println("demo运行");
return "Hello SpringMvc";
}
}
SpringMvc实现显示视图
SpringMvc显示视图也是依赖Thymeleaf
Thymeleaf也是哦Spring框架推荐使用的模板引擎,使用率是比较高的
我们已经在上面的配置中包含了pom.xml的依赖的配置
我们直接将Thymeleaf模板引擎注入到Spring容器中即可
在SpringMvcConfig类中获得代码如下
注意注入的代码不是自己编写的,不用了解具体每行代码的功能
@ComponentScan("cn.tedu.controller")
public class SpringMvcConfig {
@Bean
public ThymeleafViewResolver viewResolver(){
System.out.println("init ThymeleafViewResolver");
//设置模板保存位置为 /resources/templates/*.html
ClassLoaderTemplateResolver templateResolver =
new ClassLoaderTemplateResolver();
//模版存储文件夹
templateResolver.setPrefix("/templates/");
//模版后缀
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(true);
//创建模板引擎
SpringTemplateEngine templateEngine =
new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.setEnableSpringELCompiler(true);
//创建模版解析器
ThymeleafViewResolver viewResolver =
new ThymeleafViewResolver();
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
}
需要注意,我们模板文件(html)文件
必须放在resources/templates/文件夹下,没有的话需要创建!
创建了templates文件夹后可以在其中创建一个html文件
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>这是SpringMvc和Thymeleaf显示的页面</h1>
</body>
</html>
下面我就可以使用SpringMvc来访问这个页面了
控制器中新加一个方法来返回这个页面
代码如下
@GetMapping("/test.do")
public ModelAndView test(){
System.out.println("运行了test");
//返回的hello会被模板引擎自动添加配置好的前缀和后缀
//resources/templates/hello.html
return new ModelAndView("hello");
}
我们想让SpringMvc有用武之地需要表单来体现一下
创建一个带有表单的页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<h1>注册</h1>
<form method="post" action="handle_reg.do">
<div>
<label>用户</label>
<input type="text" name="username">
</div>
<div>
<label>密码</label>
<input type="password" name="password">
</div>
<div>
<label>年龄</label>
<input type="number" name="age">
</div>
<div>
<label>电话</label>
<input type="tel" name="phone">
</div>
<div>
<label>电邮</label>
<input type="email" name="email">
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
习题:再编写一个方法
使用reg.do的路径让这个表单页面显示在浏览器上!
使用SpringMvc接收表单信息
实现上面的功能新建一个控制器
UserController代码如下
//@RestController和@Controller的区别
//@RestController除了Controller注解的功能将当前类注入到Spring容器之外
//所有返回字符串的方法,都是直接将字符串返回相当于加了@ResponseBody
//如果想返回页面,直接返回ModelAndView对象即可
@RestController
//@RequestMapping()写在类上,表示要访问这个类中的方法,需要统一前置增加指定内容
//比如("/user") 就表示要想访问这个类中的方法需要先写"/user"
@RequestMapping("/user")
public class UserController {
//@GetMapping("/abc.do")//localhost:8080/user/abc.do
//...
@GetMapping("/reg.do")//localhost:8080/user/reg.do
public ModelAndView reg(){
return new ModelAndView("reg");
}
}
显示表单以后我们想提交信息到控制器
就像之前在Servlet类中获得表单中的信息一样
但是SpringMvc控制器完成这个操作比Servlet简单很多
代码如下
//接收表单信息的方法
//@PostMapping来接受post请求
@PostMapping("/handle_reg.do")
public String handReg(
String username,
String password,
int age,
String phone,
String email
){
System.out.println("用户名:"+username);
System.out.println("密码:"+password);
System.out.println("年龄:"+age);
System.out.println("电话:"+phone);
System.out.println("电邮:"+email);
return "OK";
}
需要注意上面的方法接收的请求是Post请求所以使用@PostMapping来接收
方法的参数必须严格按照对应表单中name属性的值来获得用户输入的信息
类型会自动转换(int age直接获取即可)
虽然这样的代码已经比Servlet简单了,但是开发大型项目可能又十几甚至更多属性的表单
我们可以再简单一些
新建一个包,包中新建一个User类
代码如下
public class User implements Serializable {
private String username;
private String password;
private int age;
private String phone;
private String email;
//省略set\get\toString
}
上面定义的类中的属性名和表单的name属性值对应
有了这个类我们就可以更简单的获得表单中的信息
代码如下
@PostMapping("/handle_reg.do")
public String handReg(User user){
System.out.println(user);
return "OK";
}
常见问题解答
1.User类对象时怎么接收到表单信息的
本质上是DispatcherServlet检测Controller方法属性的
内部是同属性的set方法为对象赋值的
赋值原则是尽量赋值
2.路径问题
/user是怎么保持的
访问/user/reg.do就已经进入了/user/目录下
表单提交action="handle_reg.do"是相对路径,是在/user/下提交的
提交结果是/user/handle_reg.do ,所以不需要编写前置的/user/
表单提交的中文信息处理
上面提交信息到Controller中如果是中文会发生乱码
为了防止乱码,回到WebApp类中添加一个方法,设置过滤器即可
//这个方法不是必须重写的
//但是表单提交中文有乱码
//添加一个过滤器防止乱码的出现
@Override
protected Filter[] getServletFilters() {
return new Filter[]{new CharacterEncodingFilter("UTF-8")};
}
控制器方法获得Request对象
我们可能仍然偶尔需要HttpServletRequest类的方法
name怎么在现有的控制器方法中获得这个对象呢?
代码如下
@PostMapping("/handle_reg.do")
public String handReg(User user, HttpServletRequest request){
System.out.println(user);
//输出客户端的ip地址
System.out.println("访问服务器的客户端地址为:"+request.getRemoteAddr());
return "OK";
}
直接再方法的参数列表中声明HttpServletRequest类型的变量即可
DispatcherServlet会自动将当前请求对象赋值为这个属性!
控制器方法接收get请求参数
get请求参数一般都是以url中?开始的
例如
http://localhost:8080/deleteUser.do?id=10&name=tom
控制器中编写代码,原理和写法和接收表单信息是一致的
//接收get请求参数的方法
@GetMapping("/get.do")
//参数的参数名必须和?后面的名称一致
public String get(int id){
System.out.println("id:"+id);
return "ok";
}
特殊参数名处理
当get请求参数名称是java关键字时,必须使用@RequestParam进行注解
代码如下
@GetMapping("/get.do")
//如果get请求参数名是特殊字符\java关键字name参数名称就无法直接对应
//需要在参数前添加@RequestParam注解
// 这个注解可以指定后门参数对象的get请求参数名
public String get(@RequestParam("if") int num){
System.out.println("num:"+num);
return "ok";
}