推荐学习在C语言中文网上springmvc
概述:
简单理解mvc就是做网站开发,前后端交互
概念和核心
- 概念:SpringMVC是Spring框架中的一个分支,是基于Java实现MVC的轻量级Web框架
- 核心:Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计的。
什么是MVC
- Model:数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
- View:负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
- Controller(调度员): 接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
- 最常用的MVC:(Model)Bean +(view) Jsp +(Controller) Servlet
MVC 设计不仅限于 Java Web 应用,还包括许多应用,比如前端、PHP、.NET 等语言。之所以那么做的根本原因在于解耦各个模块。
MVC 是 Model、View 和 Controller 的缩写,分别代表 Web 应用程序中的 3 种职责。
- 模型:用于存储数据以及处理用户请求的业务逻辑。
- 视图:向控制器提交数据,显示模型中的数据。
- 控制器:根据视图提出的请求判断将请求和数据交给哪个模型处理,将处理后的有关结果交给哪个视图更新显示。
基于 Servlet 的 MVC 模式的具体实现如下。
- 模型:一个或多个 JavaBean 对象,用于存储数据(实体模型,由 JavaBean 类创建)和处理业务逻辑(业务模型,由一般的 Java 类创建)。
- 视图:一个或多个 JSP 页面,向控制器提交数据和为模型提供数据显示,JSP 页面主要使用 HTML 标记和 JavaBean 标记来显示数据。
- 控制器:一个或多个 Servlet 对象,根据视图提交的请求进行控制,即将请求转发给处理业务逻辑的 JavaBean,并将处理结果存放到实体模型 JavaBean 中,输出给视图显示。
基于 Servlet 的 MVC 模式的流程如图 1 所示。
![JSP中的MVC模式](https://img-blog.csdnimg.cn/img_convert/d2ae4dc0f0d264559433abe04b0dea4b.gif)
springmvc第一个程序搭建
先到依赖
dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
idea搭建项目
先创建maven项目
右击点击红箭头
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183125923.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
里面就有想要的web引用
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183145765.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
eclipse搭建
创建maven时候直接修改
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183157471.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
在spirngmvc.xml配置文件写上这个
<context:component-scan base-package="com.xiong.controller"/>
web.xml写上servlet配置
<!-- 配置 DispatcherServlet:springmvc核心-->
<servlet>
<servlet-name>springmvc</servlet-name>
<!-- 关联一个springmvc一个reoures配置文件-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--设置执行级别-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--拦截的规则 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--匹配的规则 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
注意:拦截规则
url参与匹配的是哪部分?
答:匹配的时候并不是用完整的url进行匹配,而是用完整的url减去当前应用对应上下文之后的部分来 进行匹配。比如,访问localhost:8080/webdemo/login,应用上下文是localhost:8080/webdemo,参 与匹配的是/login
有四种匹配规则
-
精确匹配
中配置的项与url相应部分完全一致才能匹配上
例如
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183400422.jpg#pic_center)
当在浏览器中输入如下几种url时,都会被匹配到该servlet
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183428219.jpg#pic_center)
-
路劲匹配/*
- 全部拦截,包括jsp,图片,css等,不建议用
- 请求可以走到action中,但转到jsp会被再次拦截,不能访问到jsp
以/字符开头,并以/*结尾的字段串用于路劲匹配。
例如
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183449898.jpg#pic_center)
路劲以/user/开始,后面的路劲可以任意。比如下面的url都会被匹配:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183507617.jpg#pic_center)
而
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183542251.jpg#pic_center)
它涵盖的范围最大,它可以匹配所有的request请求。
-
扩展名匹配 *.xx
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020110618365023.jpg#pic_center)
-
缺省匹配 /
拦截所有,但不包括jsp和css等静态文件,即对静态资源放行
缺省匹配的写法是唯一的,就是<url-pattern>/</url-pattern>
。
当其他方式都匹配不到时候,就会使用默认的servlet。
匹配优先级
精确匹配>路劲匹配>扩展匹配>缺省匹配
路劲匹配和扩展名匹配不能同时使用
流程和原理
执行流程
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106183706182.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
1、 用户发送请求至前端控制器DispatcherServlet
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并 返回给DispatcherServlet。
4、 DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、 执行处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、 ViewReslover解析后返回具体View
10、 DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户
组件说明
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不 同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Handler:处理器
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的 处理器进行执行。
你有一个类接口,但是这个接口不太符合你的预期,如果要用他就需要在他的源码上进行一些修 改,这时你可以做一个适配器,在不修改原来这个接口源码的情况下,在适配器上对这个接口进 行运用,使得适配器符合你的规范。
适配器模式(Adapter Pattern),把一个类的接口变换成客户端所期待的另一种接口, Adapter模式使原本因接口不匹配(或者不兼容)而无法在一起工作的两个类能够在一起工作。 又称为转换器模式、变压器模式、包装(Wrapper)器模式(把已有的一些类包装起来,使之能 有满足需要的接口)。
例如内存卡-读卡器-笔记本,内存卡就是这个类接口,读卡器就是适配器,笔记本是系统,笔记本 通过读卡器使用内存卡。
springmvc的handler(Controller,HttpRequestHandler,Servlet等)有多种实现方式,例如 继承Controller的,基于注解控制器方式的,HttpRequestHandler方式的。由于实现方式不一 样,调用方式就不确定了。
如果正常编写调用,就需要使用多个if else判断instance of,再添加实现方式,就需要修改源 码,不符合对扩展开放,对修改关闭原则。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LuCIGzgh-1604658526488)(E:\保存\QQ截图20201105145503.jpg)]
ViewResolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即 具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
View:视图
springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。 我们最常用的视图就是jsp。
说明:在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大 组件。
需要用户开发的组件有handler、view
演变过程
继承controller接口,注册bean到容器。相当于原始servlet的写法
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106184902414.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
按理说,三大组件都需要我们配置,但是前端控制器给我们提供了默认的,所以可以不配在上面的基础上,配置处理器适配器和处理器映射器
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106184926673.jpg#pic_center)
注解开发
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106185038355.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
<bean id="dao" class="xiongxiong.dao.UserDaoMysql"></bean><!--扫描单个包进行托管容器-->
手动配置处理器映射器和处理器适配器很麻烦,可以用一个标签代替
<mvc:annotation-driven/>
访问静态资源
css,js,图片等
<mvc:default-servlet-handler/> 访问全部静态资源
<mvc:resources />
<mvc:resources mapping="resources/**/" location="/resources/"/> 这个指定的默认静态资源路径
一般静态资源会在tomat默认的servlet中加载
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106185107987.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106185128238.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
四个重要标签的作用和区别
<context:annotation-config/>
<context:component-scan/>
两个区别
源码:
Activates various annotations to be detected in bean classes: Spring's @Required and
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.
Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContext
for information on code-based alternatives to bootstrapping annotation-driven support.
翻译:
激活要在bean类中检测到的各种注释:Spring的@Required和
@Autowired,以及JSR 250的@PostConstruct, @PreDestroy和@Resource(如果有的话),
JAX-WS的@WebServiceRef(如果可用)、EJB 3的@EJB(如果可用)和JPA的
@PersistenceContext和@PersistenceUnit(如果可用)。或者,你可能
选择为这些注释激活单独的beanpostprocessor。
注意:此标记不激活Spring的@Transactional或EJB 3的处理
@TransactionAttribute注释。请考虑<tx:注释驱动的>的使用
标签的目的。
参见javadoc获得org.springframework.context. context. annotationconfigapplicationcontext
有关引导注释驱动支持的基于代码的替代方案的信息。
源码:
Scans the classpath for annotated components that will be auto-registered as
Spring beans. By default, the Spring-provided @Component, @Repository, @Service,
@Controller, @RestController, @ControllerAdvice, and @Configuration stereotypes
will be detected.
Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
annotations in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom BeanPostProcessor definitions
for handling those annotations.
Note: You may use placeholders in package paths, but only resolved against system
properties (analogous to resource paths). A component scan results in new bean definitions
being registered; Spring's PropertySourcesPlaceholderConfigurer will apply to those bean
definitions just like to regular bean definitions, but it won't apply to the component
scan settings themselves.
See javadoc for org.springframework.context.annotation.ComponentScan for information
on code-based alternatives to bootstrapping component-scanning.
翻译:
扫描类路径,寻找将被自动注册为的带注释的组件
Spring bean。默认情况下,spring提供的@Component、@Repository、@Service、
@Controller、@RestController、@ControllerAdvice和@Configuration构造型
将被检测到。
注意:此标记暗示了“注释-config”标记的效果,即激活@Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext和@PersistenceUnit
组件类中的注释,这通常是自动检测组件所需要的
(没有外部配置)。关闭“注释-配置”属性以禁用
此默认行为,例如为了使用自定义BeanPostProcessor定义
来处理这些注释。
注意:您可以在包路径中使用占位符,但只能针对system进行解析
属性(类似于资源路径)。组件扫描会产生新的bean定义
被注册;Spring的PropertySourcesPlaceholderConfigurer将应用于这些bean
定义就像常规的bean定义一样,但它不适用于组件
扫描设置。
有关org.springframework.context.annotation,请参阅javadoc。ComponentScan信息
基于代码的组件扫描引导方法。
context:component-scan/ 使用只要打一个context:component-scan/就可以 因为context:component-scan/已经包含在里面啦
<mvc:annotation-driven/>
开启两个处理器相关。。本质是servlet
<mvc:default-servlet-handler/>
走默认的servlet,也就是服务器提供的servlet。本质是servlet
springmvc 是5以上的
源码:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106185305171.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106185329692.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
自己大概网上查了一下
自己用大白话说一下:
<mvc:default-servlet-handler/> <mvc:annotation-driven/>都没有
我自己看了源码 然后我仔细看了一下 都没有话就会随机找一个进行运行
<mvc:default-servlet-handler/>有它 <mvc:annotation-driven/>没有它
一个有一个没有时所注册的三个bean都不能处理@RequestMapping注解,因此无法找到相应的Controller,进而无法进行访问路径的映射
<mvc:default-servlet-handler/> <mvc:annotation-driven/>两个都有
两个都有的话 他们会找会注册一个RequestMappingHandlerAdapter的bean容器里面进行处理
所以一般使用的话都是两个一起使用
转发和重定向
转发:客户浏览器发送 http 请求,Web 服务器接受此请求,调用内部的一个方法在容器内部完成 请求处理和转发动作,将目标资源发送给客户;在这里转发的路径必须是同一个 Web 容器下的 URL,其不能转向到其他的 Web 路径上,中间传递的是自己的容器内的 request。
在客户浏览器的地址栏中显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了 转发的。转发行为是浏览器只做了一次访问请求。
注意:看到的是一次的路径;request可以带过去
forward:/xxx
重定向:客户浏览器发送 http 请求,Web 服务器接受后发送 302 状态码响应及对应新的 location 给客户浏览器,客户浏览器发现是 302 响应,则自动再发送一个新的 http 请求,请求 URL 是新 的 location 地址,服务器根据此请求寻找资源并发送给客户。
在这里 location 可以重定向到任意 URL,既然是浏览器重新发出了请求,那么就没有什么 request 传递的概念了。在客户浏览器的地址栏中显示的是其重定向的路径,客户可以观察到地址 的变化。重定向行为是浏览器做了至少两次的访问请求。
注意:浏览器看到两次地址,request带不过去
redirect:/xxx
或者
redirect:/ip: 是可以访问其他项目的
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login() {
//转发到一个请求方法(同一个控制器类可以省略/index/)
return "forward:/index/isLogin";
}
@RequestMapping("/isLogin")
public String isLogin() {
//重定向到一个请求方法
return "redirect:/index/isRegister";
}
@RequestMapping("/isRegister")
public String isRegister() {
//转发到一个视图
return "register";
}
}
request.getAttribute()和request.getParameter()的区别
1,getAttribute表示从request范围取得设置的属性,必须要先setAttribute设置属性,才能通过getAttribute来取得,设置与取得的为Object对象类型
2,getParameter表示接收参数,参数为页面提交的参数,包括:表单提交的参数、URL重写(就是xxx?id=1中的id)传的参数等,因此这个并没有设置参数的方法(没有setParameter),而且接收参数返回的不是Object,而是String类型
注解
restful风格(了解)表述性状态转移
一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
xx/xx/xx
如:https://api.example.com/v1/zoos
GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。
之前在java写法是
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020110618545769.jpg#pic_center)
但是为了简写是
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106185516227.jpg#pic_center)
RequestMapping注解包括
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020110618555856.jpg#pic_center)
@PutMapping等于@RequestMapping 两个用法是一样的 但是在restful风格这样写比较简单不用写很长的代码
前端要是和后端代码匹配的话写这样的代码
因为浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,spring3.0添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求。
<!-- 浏览器不支持put,delete等method,由该filter将/xxx?_method=delete转换为标准的http delete方法 -->
<!--配置成浏览器可以识别的格式-->
<!-- 配置HiddenHttpMethodFilter-->
<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>
然后在页面写这个代码
<input type="hidden" name="_method" value="delect"/>
这里的value也可以写成GET或者POST只要是RequestMapping注解里面的
要是使用restful风格
这里我用springboot演示
先配置yml文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201124101945981.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
要是删除就是写成delete要是修改写成put
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201124102002243.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
就可以使用了
前端传值的话
<a th:href="@{/book/toUpdateBook/} + ${book.bookID}">修改</a> 差不多就是这样写的
<tr th:each="p: ${page}">
<td th:text="${p.id}"></td>
<td th:text="${p.name}"></td>
<td><a th:href="@{/categories/{id}(id=${p.id})}">编辑</a></td>
<td><a class="delete" th:href="@{/categories/{id}(id=${p.id})}">删除</a></td>
</tr>
@RequestMapping
- 可以加在类上,也可以加在方法上
- 可以使用路径符号
- * 表示任何路径
- ?表示单个字符的占位
- ** 表示不管中间有几层目录
- 占位符 {xxx} xxx代表你输入的id或者是name 比如在配合restful风格使用
@PathVariable
spring3.0的一个新功能:接收请求路径中占位符的值
@RequestParam
- name或者value 前后端名字不匹配 作为是前后端名字匹配
- defaultValue 作用是给默认值 一般会在分页中使用
- required 等于true false 默认是 false 要是改成true 必须要前端传值不然会报错
绑定单个请求参数值
请求方法中可以出现的参数类型
javax.servlet.ServletRequest或javax.servlet.http.HttpServletRequest
javax.servlet.ServletResponse或java.servlet.http.HttpServletResponse
javax.servlet.http.HttpSession
org.springframework.web.context.request.WebRequest或
org.springframework.web.context.request.NativeWebRequest
java.util.Locale
java.io.InputStream或java.io.Reader
java.io.OutputStream或java.io.Writer
java.security.Principal
HttpEntity<?>
java.util.Map org.springframework.ui.Model
org.springframework.ui.ModelMap
org.springframework.web.servlet.mvc.support.RedirectAttributes
org.springframework.validation.Errors
org.springframework.validation.BindingResult
org.springframework.web.bind.support.SessionStatus
org.springframework.web.util.UriComponentsBuilder
@PathVariable、@MatrixVariable注解
@RequestParam、@RequestHeader、@RequestBody、@RequestPart注解
如果需要在方法中用到以上对象,可以将其写在参数列表中,spring会创建对象并传递给方法
SpringMVC请求处理方法可返回的类型
org.springframework.web.portlet.ModelAndView
org.springframework.ui.Model
java.util.Map
org.springframework.web.servlet.View
java.lang.String
HttpEntity或ResponseEntity
java.util.concurrent.Callable
org.springframework.web.context.request.async.DeferredResult
void
返回值类型
.ModelAndView
String
void
Object
上传下载
-
导包:commons-fileupload
-
页面:post,enctype=“multipart/form-data”
<form method="post" action="test" enctype="multipart/form-data"><%--enctype="multipart/form-data"是把文件装换成二级制流闯进去的--%>
<input type="file" name="file">
<%--file 一个文件只能选择上传一个--%>
<input type="submit" value="tijiao">
</form>
-
spring.xml中配置文件上传的那个类
<!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10000000" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
-
MultipartFile
-
假如我们上传的名字一样的话就会把前面一样所以我们一般会创建一个随机名字加原本的名字但是随机名字也有冲突我们一般都有UUID创建随机数
具体使用可以看:https://blog.csdn.net/wuzhangxiong123/article/details/109532412
@RequestMapping("test")
public String test1(MultipartFile file, HttpServletRequest request) throws IOException {
String oldname=file.getOriginalFilename();
String newname= UUID.randomUUID().toString()+oldname;
String path="d:/aaaaaaa";
File director=new File(path);
if (!director.exists()) {
director.mkdirs();
}
File target=new File(path,newname);
file.transferTo(target);
// System.out.println(file.getOriginalFilename());//getOriginalFilename获取文件名字
return "login";
}
多文件上传
有两种
1.是多创建几个同样的方法 但是名字不一样
2.把他写成一个数组接收起来 但是名字一定要一样
public String test1(MultipartFile[] file, HttpServletRequest request) throws IOException {
for (MultipartFile multipartFile : file) {
System.out.println(multipartFile.getOriginalFilename());
//在里面写和上面一样的代码
}
文件下载
id |
name |
lujing |
|
1 |
期中考试题.doc |
d:/aaa/78979879.doc |
|
实现文件下载有以下两种方法:
代码如下:
编写控制器类
@Controller
public class FileDownController {
// 得到一个用来记录日志的对象,在打印时标记打印的是哪个类的信息
private static final Log logger = LogFactory
.getLog(FileDownController.class);
/**
* 显示要下载的文件
*/
@RequestMapping("showDownFiles")
public String show(HttpServletRequest request, Model model) {
// 从 workspace\.metadata\.plugins\org.eclipse.wst.server.core\
// tmp0\wtpwebapps\springMVCDemo11\下载
String realpath = request.getServletContext()
.getRealPath("uploadfiles");
File dir = new File(realpath);
File files[] = dir.listFiles();
// 获取该目录下的所有文件名
ArrayList<String> fileName = new ArrayList<String>();
for (int i = 0; i < files.length; i++) {
fileName.add(files[i].getName());
}
model.addAttribute("files", fileName);
return "showDownFiles";
}
/**
* 执行下载
*/
@RequestMapping("down")
public String down(@RequestParam String filename,
HttpServletRequest request, HttpServletResponse response) {
String aFilePath = null; // 要下载的文件路径
FileInputStream in = null; // 输入流
ServletOutputStream out = null; // 输出流
try {
// 从workspace\.metadata\.plugins\org.eclipse.wst.server.core\
// tmp0\wtpwebapps下载
aFilePath = request.getServletContext().getRealPath("uploadfiles");
// 设置下载文件使用的报头
response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment; filename="
+ toUTF8String(filename));
// 读入文件
in = new FileInputStream(aFilePath + "\\" + filename);
// 得到响应对象的输出流,用于向客户端输出二进制数据
out = response.getOutputStream();
out.flush();
int aRead = 0;
byte b[] = new byte[1024];
while ((aRead = in.read(b)) != -1 & in != null) {
out.write(b, 0, aRead);
}
out.flush();
in.close();
out.close();
} catch (Throwable e) {
e.printStackTrace();
}
logger.info("下载成功");
return null;
}
/**
* 下载保存时中文文件名的字符编码转换方法
*/
public String toUTF8String(String str) {
StringBuffer sb = new StringBuffer();
int len = str.length();
for (int i = 0; i < len; i++) {
// 取出字符中的每个字符
char c = str.charAt(i);
// Unicode码值为0~255时,不做处理
if (c >= 0 && c <= 255) {
sb.append(c);
} else { // 转换 UTF-8 编码
byte b[];
try {
b = Character.toString(c).getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
b = null;
}
// 转换为%HH的字符串形式
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0) {
k &= 255;
}
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
}
创建文件列表页面
<table>
<tr>
<td>被下载的文件名</td>
</tr>
<!--遍历 model中的 files-->
<c:forEach items="${files}" var="filename">
<tr>
<td>
<a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a>
</td>
</tr>
</c:forEach>
</table>
拦截器
在开发一个网站时可能有这样的需求:某些页面只希望几个特定的用户浏览。对于这样的访问权限控制,应该如何实现呢?拦截器就可以实现上述需求。在 Struts 2 框架中,拦截器是其重要的组成部分,Spring MVC 框架也提供了拦截器功能。
Spring MVC 的拦截器(Interceptor)与 Java Servlet 的过滤器(Filter)类似,它主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。
先继承
public class Myinter implements HandlerInterceptor {
//执行后台方法之前执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.getRequestURI();//只能拿到mvc_war_exploded/test路劲
request.getRequestURL();//拿的全部路劲
return false;
//这里的返回值要是false的话不接着往下执行 要是true的话往下继续执行
}
//后台方法完成执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
//页面渲染完成后
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
写配置
<!--拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--全部拦截-->
<mvc:mapping path="/**"/>
<!-- <mvc:exclude-mapping path=""/> 不包括谁-->
<bean class="com.xiong.inter.Myinter"></bean>
</mvc:interceptor>
</mvc:interceptors>
异常处理
继承HandlerExceptionResolver重写
public class myexe implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//ex.printStackTrace();//打印的报错信息
ModelAndView mav=new ModelAndView();
mav.setViewName("error");
return mav;
}
}
添加容器里面
<!--加载异常到容器-->
<bean class="com.xiong.exce.myexe"></bean>
<!-- 或者扫描全部包-->
<context:component-scan base-package="com.xiong.controller"/>
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106190006427.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
继承异常处理类
public class exse extends Exception{
String msssage;
public String getMsssage() {
return msssage;
}
public void setMsssage(String msssage) {
this.msssage = msssage;
}
}
哪里会报错try一下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106190023857.jpg#pic_center)
然后带着返回信息返回页面
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020110619003991.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
创建 BaseController 类,并在该类中使用 @ExceptionHandler 注解声明异常处理方法
public class BaseController {
/** 基于@ExceptionHandler异常处理 */
@ExceptionHandler
public String exception(HttpServletRequest request, Exception ex) {
request.setAttribute("ex", ex);
// 根据不同错误转向不同页面,即异常与view的对应关系
if (ex instanceof SQLException) {
return "sql-error";
} else if (ex instanceof MyException) {
return "my-error";
} else {
return "error";
}
}
}
将所有需要异常处理的 Controller 都继承 BaseController 类
@Controller
public class TestExceptionController extends BaseController{
...
}
然后在springmvc配置扫描全部
<context:component-scan base-package="controller" />
json处理
json是什么
JSON(JavaScript Object Notation, JS 对象标记)是一种轻量级的数据交换格式。与 XML 一样,JSON 也是基于纯文本的数据格式。它有对象结构和数组结构两种数据结构。
格式是{“name”:“vale”}要是还有的话那逗号隔开(,)
要是数组的话加[ “Porsche”, “BMW”, “Volvo” ]
springmvc处理json
加上一个@ResponseBody
作用:@ResponseBody的作用其实是将java对象转为json格式的数据。
@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。
jackson 默认
fastjson 阿里的 (jsonbject , .parse )
1.@ResponseBody:返回的数据 不走视图解析器,返回josn数据
2.加入json依赖,new对象,封装,返回字符串
3.mvc配置,就可以直接返回对象啦
添加jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.5</version>
</dependency>
第一种方式做
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020111519392396.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
第二种方式在xml文件添加依赖
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
然后
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201115193947775.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
ajax的使用
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201115194010216.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201115194010207.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
第一个常规 第二个是简单
ssm整合
这里有mybatis和spring整合把他拿过来然后在把springmvc配置和依赖导进来就好
https://blog.csdn.net/wuzhangxiong123/article/details/109336408
springmvc,mybatis和spring整合
依赖文件
<!--springmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- mybatis和spring -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<!--这里使用jdbc方式连接,所以导入jdbc包。如果需要用连接池,就导入对应连接池的包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
spirng配置文件 注意:spirng一般也可以不用要 直接放到springmvc中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:component-scan base-package="xiongmao.qn.pojo"></context:component-scan>
<context:annotation-config />
<!-- 加载数据库配置项 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置数据源,这里用的是jdbc的方式。数据源可以替换为任意的数据库连接池,只需要导入对应的jar 包即可 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置mybatis核心配置文件 -->
<!-- <property name="configLocation" value="classpath:mybatis.xml" /> -->
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:xiongmao/qn/mapper/*.xml" />
</bean>
<!-- <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean> -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="xiongmao.qn.mapper" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务的增强 -->
<tx:advice id="txAdvice"
transaction-manager="transactionManager">
<tx:attributes>
<!-- isolation="DEFAULT" 隔离级别
propagation="REQUIRED" 传播行为
read-only="false" 只读
timeout="-1" 过期时间
rollback-for="" -Exception
no-rollback-for="" +Exception
-->
<tx:method name="transfer" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
</beans>
mybatis配置文件 注意:mybatis一般也可以不用要 直接放到springmvc中
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 环境配置标签 -->
<!-- <settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings> -->
<typeAliases>
<package name="xiongmao.qn.pojo"/>
</typeAliases>
<!--将mapper文件加入到配置文件中 -->
<mappers>
<!-- <mapper resource="Test.xml"/> -->
<package name="xiongmao.qn.mapper"/>
</mappers>
</configuration>
springmvc配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.xiong.controller"/>
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"></property>
<property name="prefix" value="/WEB-INF/"></property>
</bean>
<!--<mvc:annotation-driven/>
<mvc:default-servlet-handler/>-->
<!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10000000" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<!--拦截器配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--全部拦截-->
<mvc:mapping path="/**"/>
<!-- <mvc:exclude-mapping path=""/> 不包括谁-->
<bean class="com.xiong.inter.Myinter"></bean>
</mvc:interceptor>
</mvc:interceptors>
<!--加载异常到容器--><!-- 或者扫描全部包-->
<bean class="com.xiong.exce.myexe"></bean>
</beans>
springmvc配置的web.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置 DispatcherServlet:springmvc核心-->
<servlet>
<servlet-name>springmvc</servlet-name>
<!-- 关联一个springmvc一个reoures配置文件-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--设置执行级别-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--拦截的规则 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--匹配规则 -->
<!--/:只匹配请求,不包括所有的.jsp
/*:匹配所有的请求,包括jsp页面 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/tologin.jsp</url-pattern>
<url-pattern>/insert.jsp</url-pattern>
</servlet-mapping>-->
<!-- 浏览器不支持put,delete等method,由该filter将/xxx?_method=delete转换为标准的http delete方法 -->
<!--配置成浏览器可以识别的格式-->
<!-- 配置HiddenHttpMethodFilter-->
<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>
数据库连接配置jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sss?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
国际化(了解)
自己写的国际化程序
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106190205666.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106190217353.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106190233973.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1emhhbmd4aW9uZzEyMw==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106190244965.jpg#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201106190244972.jpg#pic_center)
国际化是商业软件系统的一个基本要求,因为当今的软件系统需要面对全球的浏览者。国际化的目的就是根据用户的语言环境的不同向用户输出与之相应的页面,以示友好。
程序国际化已成为 Web 应用的基本要求。随着网络的发展,大部分 Web 站点面对的已经不再是本地或者本国的浏览者,而是来自全世界各国、各地区的浏览者,因此国际化成为了 Web 应用不可或缺的一部分。
Java 国际化的思想是将程序中的信息放在资源文件中,程序根据支持的国家及语言环境读取相应的资源文件。资源文件是 key-value 对,每个资源文件中的 key 是不变的,但 value 随不同国家/语言变化。
Java 程序的国际化主要通过两个类来完成。
1)java.util.Locale
用于提供本地信息,通常称它为语言环境。不同的语言、不同的国家和地区采用不同的 Locale 对象来表示。
2)java.util.ResourceBundle
该类称为资源包,包含了特定于语言环境的资源对象。当程序需要一个特定于语言环境的资源时(例如字符串资源),程序可以从适合当前用户语言环境的资源包中加载它。采用这种方式可以编写独立于用户语言环境的程序代码,而与特定语言环境相关的信息则通过资源包来提供。
为了实现 Java 程序的国际化,必须事先提供程序所需要的资源文件。资源文件的内容由很多 key-value 对组成,其中 key 是程序使用的部分,而 value 是程序界面的显示。
资源文件的命名可以有如下 3 种形式:
- baseName.properties。
- baseName_language.properties。
- baseName_language_country.properties。
baseName 是资源文件的基本名称,由用户自由定义,但是 language 和 country 必须为 Java 所支持的语言和国家/地区代码。例如:
- 中国大陆:baseName_zh_CN.properties。
- 美国:baseName_en_US.properties。
Java 中的资源文件只支持 ISO-8859-1 编码格式字符,直接编写中文会出现乱码。用户可以使用 Java 命令 native2ascii.exe 解决资源文件的中文乱码问题,使用 MyEclipse 编写资源属性文件,在保存资源文件时 MyEclipse 自动执行 native2ascii.exe 命令,因此在 MyEclipse 中资源文件不会出现中文乱码问题。
Java 支持的语言和国家
java.util.Locale类的常用构造方法如下:
public Locale(String language);
public Locale(String language, String country)。
其中,language 表示语言,它的取值是由小写的两个字母组成的语言代码。country 表示国家或地区,它的取值是由大写的两个字母组成的国家或地区代码。
实际上,Java 并不能支持所有国家和语言,如果需要获取 Java 所支持的语言和国家,开发者可以通过调用 Locale 类的 getAvailableLocales 方法获取,该方法返回一个 Locale 数组,该数组中包含了 Java 所支持的语言和国家。
下面的 Java 程序简单示范了如何获取 Java 所支持的国家和语言:
import java.util.Locale;public class Test { public static void main(String[] args) { // 返回Java所支持的语言和国家的数组 Locale locales[] = Locale.getAvailableLocales(); // 遍历数组元素,依次获取所支持的国家和语言 for (int i = 0; i < locales.length; i++) { // 打印出所支持的国家和语言 System.out.println(locales[i].getDisplayCountry() + "=" + locales[i].getCountry() + "" + locales[i].getDisplayLanguage() + "=" + locales[i].getLanguage()); } }}
Java 程序的国际化
假设有如下简单 Java 程序:
public class TestI18N { public static void main(String[] args) { System.out.println("我要向把不同国家的人民问好:您好!"); }}
为了让该程序支持国际化,需要将“我要向不同国家的人民问好:您好!”对应不同语言环境的字符串,定义在不同的资源文件中。
在 Web 应用的 src 目录下新建文件 messageResource_zh_CN.properties 和 messageResource_ en_US.properties。然后给资源文件 messageResource_zh_CN.properties 添加“hello=我要向不同国家的人民问好:您好!”内容,保存后可看到如图 1 所示的效果。
![Unicode编码资源文件](https://img-blog.csdnimg.cn/img_convert/d00e6cde0a15225ed874e14839aa5346.png)
图 1 Unicode 编码资源文件
图 1 显示的内容看似是很多乱码,实际上是 Unicode 编码文件内容。至此,资源文件 messageResource_zh_CN.properties 创建完成。
最后给资源文件 messageResource_en_US.properties 添加“hello=I want to say hello to all world!”内容。
现在将 TestI18N.java 程序修改成如下形式:
import java.util.Locale;import java.util.ResourceBundle;public class TestI18N { public static void main(String[] args) { // 取得系统默认的国家语言环境 Locale lc = Locale.getDefault(); // 根据国家语言环境加载资源文件 ResourceBundle rb = ResourceBundle.getBundle("messageResource", lc); // 打印出从资源文件中取得的信息 System.out.println(rb.getString("hello")); }}
上面程序中的打印语句打印的内容是从资源文件中读取的信息。如果在中文环境下运行程序,将打印“我要向不同国家的人民问好:您好!”。
如果在“控制面板”中将计算机的语言环境设置成美国,然后再次运行该程序,将打印“I want to say hello to all world!”。需要注意的是,如果程序找不到对应国家/语言的资源文件,系统该怎么办?
假设以简体中文环境为例,先搜索如下文件:
messageResource_zh_CN.properties
如果没有找到国家/语言都匹配的资源文件,再搜索语言匹配文件,即搜索如下文件:
messageResource_zh.properties
如果上面的文件还没有搜索到,则搜索 baseName 匹配的文件,即搜索如下文件:
messageResource.properties
如果上面 3 个文件都找不到,则系统将出现异常。
带占位符的国际化信息
在资源文件中消息文本可以带有参数,例如:
welcome={0},欢迎学习 Spring MVC。
花括号中的数字是一个占位符,可以被动态的数据替换。在消息文本中占位符可以使用 0~9 的数字,也就是说消息文本的参数最多可以有 10 个。例如:
welcome={0},欢迎学习 Spring MVC,今天是星期{1}。
如果要替换消息文本中的占位符,可以使用 java.text.MessageFormat 类,该类提供了一个静态方法 format,用来格式化带参数的文本。format 方法的定义如下:
public static String format(String pattern,Object …arguments)
其中,pattern 字符串就是一个带占位符的字符串,消息文本中的数字占位符将按照方法参数的顺序(从第二个参数开始)被替换。
替换占位符的示例代码如下:
纯文本复制
import java.text.MessageFormat;import java.util.Locale;import java.util.ResourceBundle;public class TestFormat { public static void main(String[] args) { // 取得系统默认的国家语言环境 Locale lc = Locale.getDefault(); // 根据国家语言环境加载资源文件 ResourceBundle rb = ResourceBundle.getBundle("messageResource", lc); // 从资源文件中取得的信息 String msg = rb.getString("welcome"); // 替换消息文本中的占位符,消息文本中的数字占位符将按照参数的顺序 // (从第二个参数开始)被替换,即“我”替换{0}、“5”替换{1} String msgFor = MessageFormat.format(msg, "我", "5"); System.out.println(msgFor); }}
Spring MVC 的国际化是建立在 Java 国际化的基础之上的,Spring MVC 框架的底层国际化与 Java 国际化是一致的,作为一个良好的 MVC 框架,Spring MVC 将 Java 国际化的功能进行了封装和简化,开发者使用起来会更加简单、快捷。
由《Java国际化概念和使用介绍》教程可知国际化和本地化应用程序时需要具备以下两个条件:
- 将文本信息放到资源属性文件中。
- 选择和读取正确位置的资源属性文件。
下面讲解第二个条件的实现。
Spring MVC加载资源属性文件
在 Spring MVC 中不能直接使用 ResourceBundle 加载资源属性文件,而是利用 bean(messageSource)告知 Spring MVC 框架要将资源属性文件放到哪里。示例代码如下:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleM essageSource"> <property name="basenames"> <list> <value>/WEB-INF/resource/messages</value> <value>/WEB-INF/resource/labels</value> </list> </property></bean>
语言区域的选择
在 Spring MVC 中可以使用语言区域解析器 bean 选择语言区域,该 bean 有 3 个常见实现,即 AcceptHeaderLocaleResolver、SessionLocaleResolver 和 CookieLocaleResolver。
1)AcceptHeaderLocaleResolver
根据浏览器 Http Header 中的 accept-language 域设定(accept-language 域中一般包含了当前操作系统的语言设定,可通过 HttpServletRequest.getLocale 方法获得此域的内容)。
改变 Locale 是不支持的,即不能调用 LocaleResolver 接口的 setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale)方法设置 Locale。
2)SessionLocaleResolver
根据用户本次会话过程中的语言设定决定语言区域(例如用户进入首页时选择语言种类,则此次会话周期内统一使用该语言设定)。
3)CookieLocaleResolver
根据 Cookie 判定用户的语言设定(Cookie 中保存着用户前一次的语言设定参数)。
由上述分析可知,SessionLocaleResolver 实现比较方便用户选择喜欢的语言种类,教程中使用该方法进行国际化实现。
下面是使用 SessionLocaleResolver 实现的 bean 定义:
如果采用基于 SessionLocaleResolver 和 CookieLocaleResolver 的国际化实现,必须配置 LocaleChangeInterceptor 拦截器,示例代码如下:
mvc:interceptors
</mvc:interceptors>
使用 message 标签显示国际化信息
在 Spring MVC 框架中可以使用 Spring 的 message 标签在 JSP 页面中显示国际化消息。在使用 message 标签时需要在 JSP 页面的最前面使用 taglib 指令声明 spring 标签,代码如下:
<%@taglib prefix=“spring” uri=“http://www.springframework.org/tags”%>
message 标签有以下常用属性。
- code:获得国际化消息的 key。
- arguments:代表该标签的参数。如果替换消息中的占位符,示例代码为“<spring:message code=“third” arguments=“888,999” />”,third 对应的消息有两个占位符 {0} 和 {1}。
- argumentSeparator:用来分隔该标签参数的字符,默认为逗号。
- text:code 属性不存在,或指定的 key 无法获取消息时所显示的默认文本信息。
在许多成熟的商业软件系统中可以让用户自由切换语言,而不是修改浏览器的语言设置。一旦用户选择了自己需要使用的语言环境,整个系统的语言环境将一直是这种语言环境。
Spring MVC 也可以允许用户自行选择程序语言。本章通过 Web 应用 springMVCDemo09 演示用户自定义切换语言,在该应用中使用 SessionLocaleResolver 实现国际化,具体步骤如下:
1)创建应用
创建应用 springMVCDemo09,并导入 Spring MVC 相关的 JAR 包。
2)创建国际化资源文件
在 WEB-INF/resource 目录下创建中英文资源文件 messages_en_US.properties 和 messages_zh_CN.properties。
messages_en_US.properties 的内容如下:
first=first
second=second
third={0} third{1}
language.en=English
language.cn=Chinese
messages_zh_CN.properties 的内容如下:
first=\u7B2C\u4E00\u9875
second=\u7B2C\u4E8C\u9875
third={0} \u7B2C\u4E09\u9875 {1}
language.cn=\u4E2D\u6587
language.en=\u82F1\u6587
3)创建视图 JSP 文件
在 WEB-INF/jsp 目录下创建 3 个 JSP 文件,即 first.jsp、second.jsp 和 third.jsp。
first.jsp 的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="spring" uri="http://www.springframework.org/tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body> <a href="${pageContext.request.contextPath }/i18nTest?locale=zh_ CN"> <spring:message code="language.cn" /> </a> -- <a href="${pageContext.request.contextPath }/i18nTest?locale=en_US"> <spring:message code="language.en" /> </a> <br> <br> <spring:message code="first" /> <br> <br> <a href="${pageContext.request.contextPath }/my/second"> <spring:message code="second" /> </a></body></html>
second.jsp 的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="spring" uri="http://www.springframework.org/tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body> <spring:message code="second"/><br><br> <a href="${pageContext.request.contextPath }/my/third"> <spring:message code="third" arguments="888,999"/> </a></body></html>
third.jsp 的代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="spring" uri="http://www.springframework.org/tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body> <spring:message code="third" arguments="888,999" /> <br> <br> <a href="${pageContext.request.contextPath }/my/first"> <spring:message code="first" /> </a></body></html>
4)创建控制器类
该应用有两个控制器类,一个是 I18NTestController 处理语言种类选择请求,一个是 MyController 进行页面导航。在 src 目录中创建一个名为 controller 的包,并在该包中创建这两个控制器类。
I18NTestController.java 的代码如下:
package controller;import java.util.Locale;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class I18NTestController { @RequestMapping("/i18nTest") /** * locale接收请求参数locale值,并存储到session中 */ public String first(Locale locale) { return "first"; }}
MyController 的代码如下:
package controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controller@RequestMapping("/my")public class MyController { @RequestMapping("/first") public String first() { return "first"; } @RequestMapping("/second") public String second() { return "second"; } @RequestMapping("/third") public String third() { return "third"; }}
5)创建配置文件
在 WEB-INF 目录下创建配置文件 springmvc-servlet.xml 和 web.xml。web.xml 的代码与 Spring MVC 简单应用的相同,这里不再赘述。springmvc-servlet.xml 的代码如下:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 使用扫描机制扫描包 --> <context:component-scan base-package="controller" /> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 国际化操作拦截器,如果采用基于Session/Cookie则必须配置 --> <mvc:interceptors> <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /> </mvc:interceptors> <!-- 存储区域设置信息 --> <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"> <property name="defaultLocale" value="zh_CN"></property> </bean> <!-- 加载国际化资源文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- <property name="basename" value="classpath:messages" /> --> <property name="basename" value="/WEB-INF/resource/messages" /> </bean></beans>
6)发布应用并测试
首先将 springMVCDemo09 应用发布到 Tomcat 服务器并启动 Tomcat 服务器,然后通过地址“http://localhost:8080/springMVCDemo08/my/first”测试第一个页面,运行结果如图 1 所示。
![中文环境下first.jsp的运行结果](https://img-blog.csdnimg.cn/img_convert/4f71f316d6180ddf6c6b54816c433eb7.png)
图 1 中文环境下 first.jsp 的运行结果
单击图 1 中的“第二页”超链接,打开 second.jsp 页面,运行结果如图 2 所示。
![中文环境下second.jsp的运行结果](https://img-blog.csdnimg.cn/img_convert/2338c1bab07eae11caf629a99c33d9be.png)
图 2 中文环境下second.jsp的运行结果
单击图 2 中的“第三页”超链接,打开 third.jsp 页面,运行结果如图 3 所示。
![中文环境下third.jsp的运行结果](https://img-blog.csdnimg.cn/img_convert/dae5cd37d65f76d4ee485283210bb1a0.png)
图 3 中文环境下third.jsp的运行结果
单击图 1 中的“英文”超链接,打开英文环境下的 first.jsp 页面,运行结果如图 4 所示。
![英文环境下first.jsp的运行结果](https://img-blog.csdnimg.cn/img_convert/81d6f69b783bf297516b9a3bd4662afb.png)
图 4 英文环境下 first.jsp 的运行结果
单击图 4 中的 second 超链接,打开英文环境下的 second.jsp 页面,运行结果如图 5 所示。
![英文环境下second.jsp的运行结果](https://img-blog.csdnimg.cn/img_convert/e8d0882f39bdba2f4e4c31beaa135fae.png)
图 5 英文环境下 second.jsp 的运行结果
单击图 5 中的 third 超链接,打开英文环境下的 third.jsp 页面,运行结果如图 6 所示。
![英文环境下third.jsp的运行结果](https://img-blog.csdnimg.cn/img_convert/af51535ff51b0dee1ef688b79c863783.png)
图 6 英文环境下 third.jsp 的运行结果