1. Spring
1.1. 作用
框架:一套已经由他人编写完成的代码,用于解决特定的问题,可能会改变原有编程方式,或框架有它自身的运行流程。通常表现为某一个或多个jar包。
Spring框架的主要作用就是:创建和管理对象。
1.2. 知识点
1.2.1. 配置节点(*)
1.2.2. 单例:scope属性
1.2.3. 懒加载:lazy-init属性
1.2.4. 生命周期方法:init-method和destroy-method属性
1.2.5. 注入属性的值:节点(*)
1.2.6. Spring表达式
1.2.7. 注入集合类型的值:List、Set、Map、Perperties(*)
1.2.8. 自动装配:byType、byName(*,理解)
1.2.9. 注解(*)
@Componenet、@Controller、@Service、@Repository、@Named
@Scope
@Lazy
@PostConstruct、@PreDestroy
@Autowired、@Resource
@Value
(以上部分注解来自JavaEE,需要添加Tomcat运行环境后才可以使用)
1.2.10. 组件扫描(*)
<component-scan base-package="cn.huang.spring" />
2. SpringMVC
2.1. 作用
SpringMVC解决了V与C的交互问题。
在传统的基于Servlet的编程中,最大的问题在于每个Servlet只用于处理1种请求,例如某Servlet只处理注册请求,而登录功能则需要另一个Servlet,同理,退出登录、修改资料、修改密码等等功能都需要有对应的Servlet,随着项目的功能的增加,所需的Servlet的数量就会越来越多,也会导致:项目运行时,有大量的Servlet占用了服务器的内存空间!
所以,在SpringMVC中,只使用了1个DispatcherServlet
去接收所有的请求,然后进行分发到不同的Controller
中的某个方法,从而,减少Servlet
对象的数量!
SpringMVC还提高了编码效率。
2.2. 开发流程
2.2.1. 创建项目
创建Maven Project,勾选Create a simple project
,然后,Group Id
通常填当前项目的根包,例如cn.huang.spring
,Artifact Id
可以使用项目名称,例如SPRINGMVC-01-HELLOWORLD
,Packaging
选择war
,然后点击Finish,以创建项目。
默认创建的项目中并不包含web.xml
文件,所以,必须生成该文件,避免项目报错。
在pom.xml
中添加spring-mvc
的依赖代码:
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.8.RELEASE</version>
</dependency>
</dependencies>
然后,添加Tomcat运行环境。
然后,复制此前项目中的Spring配置文件spring-mvc.xml
到当前项目中,并删除已有的配置代码,除非你确定那些代码是你需要的。
所以,以后每次创建新的项目后,都应该:1) 生成web.xml,2) 添加依赖,3) 添加Tomcat运行环境,4) 复制Spring配置文件。
5)添加组件扫描
2.2.2. 配置web.xml
因为在SpringMVC中,使用了DispatcherServlet
接收所有的请求,然后再分发出去,所以,首先必须配置DispatcherServlet
,使得它能初始阶段就运行,并接收所有请求!
即使使用了框架,核心技术其实是没有发生变化的,所以,既然要配置DispatcherServlet
,就必须在web.xml
中添加配置:
<!-- 配置是哪个Servlet -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 当Servlet被初始化时加载Spring配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 当Tomcat启动时就初始化当前Servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置Servlet对应的请求路径 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
以上代码中,以后可能调整的有:<param-value>classpath:springmvc.xml</param-value>
中Spring配置文件的文件名;<url-pattern>*.do</url-pattern>
中接收的请求的名称。
当以上配置完成后,应该:当Tomcat启动时,就会初始化DispatcherServlet
,用于接收*.do
请求,当DispatcherServlet
被初始化时,就会加载Spring的配置文件(springmvc.xml---spring配置文件名自定义)!
2.2.3. 设计目标
希望发出的请求路径是/login.do
,并且,显示出webapp/WEB-INF/login.jsp
。
2.2.4. 控制器
在改进的做法中,不必再配置HandlerMapping
!
处理请求的一定是控制器,所以,创建控制器类:cn.huang.spring.controller.UserController
,即希望所有关于用户的操作的请求,都交给这个控制器来处理!控制器类都应该是整个项目的关键组件,是应该交给Spring进行管理的,所以,使用@Controller(@Controller注解等同于@Component)
注解这个类,并且,在Spring的配置文件中,添加组件扫描。
注意:这种做法不需要实现Controller接口!并且,处理请求的方法可以自行定义返回值类型、方法名称、参数列表!
此次的目标是显示登录页面,所以,方法名可以是showLogin
,由于不需要参数,所以,方法的参数列表为空,处理结束时,不需要转发任何数据,只需要确定视图组件名称即可,所以,返回值类型设计为String
。
public String showLogin() {
return "login"; // WEB-INF/login.jsp
}
最后,为了确保/login.do
请求能够被这个方法来处理,需要为这个方法添加注解:
@RequestMapping("login.do")
public String showLogin() {
return "login"; // WEB-INF/login.jsp
}
添加注解后,就产生了请求路径与方法的映射关系。即:当接收到login.do
请求后,就会调用以上showLogin()
方法!
2.2.5. 视图解析器
在Spring的配置中添加关于视图解析器的配置:
<!-- 配置视图解析器:根据视图名称得到视图资源 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前缀 -->
<property name="prefix" value="/WEB-INF/" />
<!-- 配置后缀 -->
<property name="suffix" value=".jsp" />
</bean>
2.2.6. 创建视图组件
由于视图解析器配置的前缀是/WEB-INF/
,后缀是.jsp
,而控制器返回的视图名称是login
,所以,此次响应的视图组件应该是/WEB-INF/login.jsp
,所以,在/WEB-INF/
下创建名为login.jsp
的文件即可完成响应。
2.2.7. 常见问题
问题描述:
警告: No mapping found for HTTP request with URI [/SPRINGMVC-02-REQUESTMAPPING/login1.do] in DispatcherServlet with name 'SpringMVC'
问题原因:没有找到请求路径对应的映射,无法处理这个URI对应的请求!
解决方法:
-
请检查控制器类是否被Spring管理,即:在Spring配置中是否开启了组件扫描,且扫描的位置是否是控制器类的包名或其父级包名!并且,控制器类是否添加了
@Controller
注解! -
请检查是否正确的配置了
@RequestMapping
,即:在@RequestMapping
中填写的请求路径,与浏览器地址栏中输入的路径需要保持完全一致,包括.do
后缀! -
请检查
web.xml
中配置的DispatcherServlet
接收的请求映射,应该是*.do
!
3. 关于@RequestMapping注解
3.1. 基本使用
使用@RequestMapping
可以配置请求路径与处理请求的方法之间的映射关系!
使用@RequestMapping
可以修饰方法,也可以修饰类!即:在类的声明之前也可以添加该注解,例如:
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping("login.do")
public String showLogin() {
return "login";
}
}
则访问时的请求路径应该是:user/login.do
所以,同样是使用@RequestMapping
注解,在类之前加的注解并不能取代方法之前的注解!如果在类和方法之前都添加了该注解,其实是组合使用的!
通常,建议在每个控制器类之前都使用@RequestMapping
进行注解!
在配置注解时,其中的路径可以添加/
,也可以不添加,也就是:
/user /login.do
/user login.do
user /login.do
user login.do
以上4种做法都是可以正确运行的!推荐使用第1种,也就是类和方法之前的注解都添加/
。
4. 接收请求参数
4.1. 设计目标
在reg.jsp
中添加用户名和密码的输入框,当点击提交按钮后,以POST
的方式将请求提交到/user/handle_reg.do
,并且 ,控制器接收到请求后,能够获取用户填写的用户名和密码。
4.2. 【不推荐】通过HttpServletRequest参数获取请求参数
在处理请求的方法中,添加HttpServletRequest
类型的参数,然后调用参数对象的String getParameter(String)
方法即可获取请求参数:
@RequestMapping("/handle_reg.do")
public String handleReg(HttpServletRequest request) {
System.out.println("UserController.handleReg() > 准备接收请求参数...");
// getParameter()的参数必须与jsp页面中控件的name保持一致
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username=" + username);
System.out.println("password=" + password);
return ""; // 暂不关心返回的视图名,后续运行会出现404
}
4.3. 练习
在界面上添加:要求输入年龄AGE
,并且,在控制器接收它的值,要求是Integer
类型的!
4.4. 【推荐】直接在处理请求的方法中声明所需的参数
将所需的参数列表直接添加在处理请求的方法中即可:
public String handleReg(String username, String password,
Integer age) {
System.out.println("UserController.handleReg() > 准备接收请求参数...");
// getParameter()的参数必须与jsp页面中控件的name保持一致
System.out.println("username=" + username);
System.out.println("password=" + password);
System.out.println("age=" + age);
return "a"; // 暂不关心返回的视图名,后续运行会出现404
}
使用这种做法,无须调用HttpServletRequest
对象的getParameter()
方法,甚至都不需要考虑类型转换问题,例如所需的age
是Integer
类的,则直接声明参数Integer age
即可,SpringMVC框架会自动的转换类型!
注意:使用这种做法,必须前后端使用的名称保持一致,例如前端页面中标签的name值是username,则后端控制器的方法中的参数名称也必须是username,如果不一致,则后端控制器获取到的值将是null值!
注意:如果前端页面没有输入值,则控制器接收到的是空字符串,即"",如果前端页面根本就没有提交这个名称的参数,则控制器接收到的是null!
由于前后端可能是不同的开发团队完成的,则很可能出现名称不一致的问题,针对这种问题,可以在参数之前添加@RequestParam("前端提交的参数名")
来解决:
@RequestMapping("/handle_reg.do")
public String handleReg(
@RequestParam("username") String name,
String password, Integer age) {
System.out.println("UserController.handleReg() > 准备接收请求参数...");
// getParameter()的参数必须与jsp页面中控件的name保持一致
System.out.println("name=" + name);
System.out.println("password=" + password);
System.out.println("age=" + age);
return "a"; // 暂不关心返回的视图名,后续运行会出现404
}
注意:当添加了@RequestParam()注解后,该参数默认是必须提交的,如果没有提交,则报错,该问题后续在@RequestParam专题中详解。
其它
1. 编码规范
代码的可维护性是评价项目的非常重要的指标之一!其中,代码的编码规范就是最基础的表现!
首先,命名必须规范:
-
包(package)名必须全部使用小写字母,例如
cn.tedu.spring.Controller
这样的包名就是不对的,其中的Controller
子包的首字母不应该大写! -
所有的类、接口的首字母必须大写,如果名称由多个单词组成,第2个单词开始,每个单词的首字母也必须是大写的,例如:
NullPointerException
、FileNotFoundException
、ArrayIndexOutOfBoundsException
…… -
所有的属性、方法、局部变量、参数的名称都必须是首字母小写,如果名称由多个单词组成,第2个单词开始,每个单词的首字母也必须是大写的
-
所有的常量的名称中,每个字母都必须是大写的,如果由多个单词组成,则各单词之间使用下划线分隔,例如:
state_ok
应该写成STATE_OK
-
绝大部分的属性应该使用名词,例如:
name
、age
…… -
绝大部分的方法应该使用动词作为前缀,例如:
setName
、getName
-
不遵守以上命名原则的属性或方法应该是疑问类型的属性或方法,例如:
isAlive
、hasNext
,即使用is
或has
作为前缀
代码的版式也非常重要:
- 在类中,每个方法之间、属性与方法之间,应该添加1行空白
如果对代码的正确版式不太了解,可以使用Eclipse的Source
菜单中的Format
指令,使Eclipse来帮助排版!
其它……
2. 请求类型的GET与POST
发出请求
只能通过表单(Form)或Javascript代码发出POST请求,而发出GET请求的方式则更多,除了这2种做法以外,还可以通过改变浏览器的地址栏中的URL来发出GET请求!所以,发GET请求比发POST请求更加简单!
传输特点
GET请求的参数会暴露在URL中,不适合传输较私密的数据,例如密码,并且,受到URL长度的限制,GET请求不适合传递大量的数据,例如发邮件、上传文件都不可以使用GET请求!
POST请求的参数不会暴露在URL中,可以传输任何数据(传输过程没有额外的加密处理),并且,传输数据没有长度限制!
相比之下,POST请求更加有优势,但是,POST请求的发出限制略高,不便于刷新,并且,无法分享页面!
3. 查看项目的错误
如果项目结构(Eclipse的左侧)提示了任何错误,都应该在Problems
面板中查看详情,有些错误可能并不体现在某个文件或代码中。
如果Eclipse默认没有显示该面板,可以点击Window
菜单中的Show View
项打开,如果在Show View
下仍没有Problems
,可以选择Other
项再查找。
4. 切换JDK/JRE版本
移除旧版本
在Libraries
下,对旧版的JDK/JRE点右键,选择Build Path
中的Remove ...
选项,即可移除。
添加新版本
对项目名称点右键,选择Build Path
中的Configure
,在弹出的对话框中,选择Libraries
选项卡,然后点击右侧的Add Library
按钮,在弹出的新对话框中选择JRE System Library
并点击Next
,通常在下个界面中第3项即是当前系统安装的JDK/JRE版本!
如果在这个面板中没有所需的JDK/JRE版本,则点击Installed JREs
按钮并浏览到本机中安装JDK/JRE的目录进行选择即可。