一、系统标准三层架构
主流的开发架构一般有两种,一种是 C/S 架构,即客户端/服务器,另一种是 B/S 架构,也就是浏览器/服务器。Java非常适合用于B/S架构的开发,在B/S 架构中,系统被分为标准的三层架构,包括:表现层、业务层、持久层。三层架构各司其职,协调运转,构成了一个完整的网站架构,如下图:
1.1Web 表现层
负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层, web 需要接收 http 请求,完成 http 响应,表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。它的设计一般都使用 MVC 模型
表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
1.2 Service业务层
负责业务逻辑处理,和我们开发项目的需求息息相关。 web 层依赖业务层,但是业务层不依赖 web 层。同时业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性,那么应该在业务层进行事务控制。
1.3 Dao持久层
负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行曾删改查的
二、MVC模型
MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,
是一种用于设计创建 Web 应用程序表现层的模式。 MVC 中每个部分各司其职:
Model(模型)
通常指的就是我们的数据模型。作用一般情况下用于封装数据。
View(视图)
通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。通常视图是依据模型数据创建的。
Controller(控制器)
是应用程序中处理用户交互的部分。 作用一般就是处理程序逻辑的。
三、SpringMVC
3.1 什么是SpringMVC?
SpringMVC 就是Web表现层的一种框架,是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,随着 Spring3.0 的发布, SpringMVC全面超越 Struts2,成为最优秀的 MVC 框架。
它通过一套注解(@Controller),让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。
3.2 SpringMVC在三层结构中的位置
下面引用Spring官网中的一张图来描述SpringMVC在三层架构中的位置。
3.3 对比分析SpringMVC和Struts2
共同点
- 它们都是表现层框架,都是基于 MVC 模型编写的。
- 它们的底层都离不开原始 ServletAPI。
- 它们处理请求的机制都是一个核心控制器。
区别
- Spring MVC 的入口是 Servlet(即前端控制器), 而 Struts2 是 Filter
- Spring MVC 是基于方法设计的,而 Struts2 是基于类, Struts2 每次执行都会创建一个动作类。所以 Spring MVC 会稍微比 Struts2 快些。
- Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便
(JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。 ) - Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提升,尤其是 struts2 的表单标签,远没有 html 执行效率高。
四、参数绑定
4.1 绑定机制
在web层中传给业务层的数据都是基于 key=value 形式的。SpringMVC 绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的
示例
JSP代码
<a href="hello/testId?id=zhangsa">点击发送id到业务层</a>
业务层代码
@Controller
@RequestMapping(path = "/hello")
public class HelloController {
@RequestMapping(path = "/testId")
public String sayHello(String id){
System.out.println(id);
return "success";
}
}
必须保证超链接中的属性名和RequestMap对应的方法参数名保持一致
4.2 支持绑定的数据类型
-
基本类型参数
包括基本类型和 String 类型 -
POJO 类型参数
包括实体类,以及关联的实体类 -
数组和集合类型参数:
包括 List 结构和 Map 结构的集合(包括数组)
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。
4.3 使用要求
-
如果是基本类型或者 String 类型
要求我们的参数名称必须和控制器中方法的形参名称保持一致。 (严格区分大小写) -
如果是 POJO 类型,或者它的关联对象
要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。 -
如果是集合类型,有两种方式
第一种:
要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。给 List 集合中的元素赋值, 使用下标。给 Map 集合中的元素赋值, 使用键值对。第二种:
接收的请求参数是 json 格式数据。需要借助一个注解实现。
前端代码
<form action="account/updateAccount" method="get">
ID:<input type="text" name="uid"><br/>
name:<input type="text" name="username"><br/>
<%--测试数组类型--%>
province:<input type="text" name="address.province"><br/>
city:<input type="text" name="address.city"><br/>
<%--测试List集合类型--%>
account1:<input type="text" name="accounts[0].name">
money:<input type="text" name="account[0].money"><br/>
account2:<input type="text" name="account[1].name" >
money:<input type="text" name="account[1].money" ><br/>
<%--测试Map集合类型--%>
account3:<input type="text" name="accountMap['one'].name" >
money:<input type="text" name="accountMap['one'].money" ><br/>
account4:<input type="text" name="accountMap['two'].name" >
money:<input type="text" name="accountMap['two'].money" ><br/>
<input type="submit" value="提交">
</form>
控制器代码
@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/updateAccount")
public String updateAccount(User user){
System.out.println("执行成功"+user);
return "success";
}
}
请求参数乱码问题
需要在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>
自定义类型转换器
1.自定义一个类实现Converter 接口
public class StringToDate implements Converter<String,Date> {
@Override
public Date convert(String s) {
if (s==null){
throw new RuntimeException("请传入正确参数");
}
DateFormat format=new SimpleDateFormat("yyyy-MM-dd");
try{
return format.parse(s);
} catch (ParseException e) {
throw new RuntimeException("类型转换失败");
}
}
}
2.在 spring 配置文件中配置类型转换器
<!--配置类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.gzgs.utils.StringToDate"/>
</set>
</property>
</bean>
3.在 annotation-driven 标签中引用配置的类型转换服务
<!-- 开启注解转换器支持-->
<mvc:annotation-driven conversion-service="conversionService"/>
四、常用注解
4.1@RequestParam
作用:把请求中指定名称的参数给控制器中的形参赋值。
属性
- value: 请求参数中的名称。
- required:请求参数中是否必须提供此参数。 默认值: true。表示必须提供,如果不提供将报错。
示例
jsp 中的代码:
<!-- requestParams 注解的使用 -->
<a href="springmvc/useRequestParam?name=test">requestParam 注解</a>
Controller代码:
@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,
@RequestParam(value="age",required=false)Integer age){
System.out.println(username+","+age);
return "success";
}
4.2 @RequestBody
作用:用于获取请求体内容。 直接使用得到是 key=value&key=value…结构的数据,get 请求方式不适用。
属性
- required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值
为 false, get 请求得到是 null。
示例
jsp 中的代码:
<!-- post 请求 jsp 代码 -->
<form action="springmvc/useRequestBody" method="post">
用户名称: <input type="text" name="username" ><br/>
用户密码: <input type="password" name="password" ><br/>
用户年龄: <input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
<!--get 请求 jsp 代码:-->
<a href="springmvc/useRequestBody?body=test">requestBody 注解 get 请求</a>
Controller代码:
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
System.out.println(body);
return "success";
}
4.3 @PathVaribale
作用:用于绑定 url 中的占位符。 例如:请求 url 中 /delete/{id}, 这个{id}就是 url 占位符。url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性
- value: 用于指定 url 中占位符名称。
- required:是否必须提供占位符。
示例
jsp 中的代码:
<a href="springmvc/usePathVariable/100">pathVariable 注解</a>
Controller代码:
@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return "success";
}
4.4 @RequestHeader
作用:用于获取请求消息头。(不怎么用)
属性
- value:提供消息头名称
- required:是否必须有此消息头
示例
jsp 中的代码:
<a href="springmvc/useRequestHeader">获取请求消息头</a>
Controller代码:
@RequestMapping("/useRequestHeader")
public String useRequestHeader(@RequestHeader(value="Accept-Language",
required=false)String requestHeader){
System.out.println(requestHeader);
return "success";
}
4.5 @CookieValue
作用:用于把指定 cookie 名称的值传入控制器方法参数。
属性
- value:指定 cookie 的名称。
- required:是否必须有此 cookie。
示例
jsp 中的代码:
<a href="springmvc/useCookieValue">绑定 cookie 的值</a>
Controller代码:
@RequestMapping("/useCookieValue")
public String useCookieValue(@CookieValue(value="JSESSIONID",required=false)String cookieValue){
System.out.println(cookieValue);
return "success";
}
4.6 @ModelAttribute
作用
该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性
value:用于获取数据的 key。 key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
示例
jsp 中的代码:
<a href="springmvc/testModelAttribute?username=test">测试 modelattribute</a>
Controller代码:
/**
* 被 ModelAttribute 修饰的方法
* @param user
*/
@ModelAttribute
public void showModel(User user) {
System.out.println("执行了 showModel 方法"+user.getUsername());
}
/**
* 接收请求的方法
* @param user
* @return
*/
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("执行了控制器的方法"+user.getUsername());
return "success";
}
4.7 @SessionAttribute
作用 :用于多次执行控制器方法间的参数共享
属性
- value:用于指定存入的属性名称
- type:用于指定存入的数据类型
示例
jsp 中的代码:
<!-- SessionAttribute 注解的使用 -->
<a href="springmvc/testPut">存入 SessionAttribute</a>
<hr/>
<a href="springmvc/testGet">取出 SessionAttribute</a>
<hr/>
<a href="springmvc/testClean">清除 SessionAttribute</a>
Controller代码:
@Controller("sessionAttributeController")
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class})
public class SessionAttributeController {
@RequestMapping("/testPut")
public String testPut(Model model){
model.addAttribute("username", "泰斯特");
model.addAttribute("password","123456");
model.addAttribute("age", 31);
//跳转之前将数据保存到 username、 password 和 age 中,因为注解@SessionAttribute 中有
这几个参数
return "success";
}
@RequestMapping("/testGet")
public String testGet(ModelMap model){
System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a
ge"));
return "success";
}
@RequestMapping("/testClean")
public String complete(SessionStatus sessionStatus){
sessionStatus.setComplete();
return "success";
}
}
本博客纯属个人学习笔记,学习资源来自黑马训练营,如有错误,感激指正