咱们开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序
使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构
三层架构
表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
业务层:处理公司具体的业务逻辑的
持久层:用来操作数据库的
SpringMVC的概述
SpringMVC在三层架构中的位置
SpringMVC的优势
SpringMVC和Struts2框架的对比
springMVC与Struts2的区别(面试问到):我没用过Struts2框架,但我了解过他们之间的区别
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 执行效率高。
创建WEB工程,在创建的时候添加一对键值对:archetypeCatalog - internal 能解决maven工程创建过慢的问题。然后在pom.xml中导入开发的jar包
<properties>
<spring.version>5.0.2.RELEASEspring.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.0version>
<scope>providedscope>
dependency>
dependencies>
配置核心的控制器(配置DispatcherServlet)
在web.xml配置文件中核心控制器DispatcherServlet
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
编写springmvc.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!-- 配置视图解析器对象 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 开启SpringMVC框架注解的支持 -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
编写index.jsp和HelloController控制器类
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
入门程序
入门跳转
HelloController
package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 控制器
*/
@Controller
public class HelloController {
/**
* 接收请求
*/
@RequestMapping(path = "/hello")
public String sayHello(){
System.out.println("Hello SpringMVC!");
return "success";
}
}
在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
入门成功
启动Tomcat服务器,进行测试
RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
RequestMapping注解可以作用在方法和类上
RequestMapping的属性
path(常用) :指定请求路径的url
value(常用) :value属性和path属性是一样的
method(常用) :指定该方法的请求方式。属性值是一个枚举类型的数组
params 指定限制请求参数的条件。要求请求参数的 key 和 value 必须和配置的一模一样。
例如:
- params = {
"accountName"},表示请求参数必须有 accountName
- params = {
"username=zhangsan"},表示请求参数中必须含有username,且它的值必须是zhangsan
- params = {
"moeny!100"},表示请求参数中 money 不能是 100。
JSP中可以使用?拼接请求参数:
href="user/testRequestMapping?username=zhangsan"
headers 发送的请求中必须包含的请求头
提交表单的name和参数的名称是相同的
区分大小写
代码如下:
请求参数绑定
2. 控制器代码
/**
* 请求参数绑定入门
* @return
*/
@RequestMapping("/testParam")
public String testParam(String username,String password){
System.out.println("执行了...");
System.out.println("用户名:"+username);
System.out.println("密码:"+password);
return "success";
}
提交表单的name和JavaBean中的属性名称需要一致
如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:
address.name
代码如下:
封装到实体类,类中有引用属性
/**
* 将请求参数封装到实体类中
* @param account
* @return
*/
@RequestMapping("/saveAccount")
public String saveAccount(Account account){
System.out.println("执行了...");
System.out.println(account);
return "success";
}
集合的数据类型
private List<User> list;
private Map<String,User> map;
JSP页面编写方式:list[index].属性 map[key].属性
用户姓名:<input type="text" name="list[0].uname"><br/>
用户年龄:<input type="text" name="list[0].age"><br/>
用户姓名:<input type="text" name="map['one'].uname"><br/>
用户年龄:<input type="text" name="map['one'].age"><br/>
在web.xml中配置Spring提供的过滤器类
<filter>
<filter-name>characterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>characterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明
Spring框架内部会默认进行数据类型转换。
如果想自定义数据类型转换,可以实现Converter的接口
自定义类型转换器
package cn.itcast.utils;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 自定义类型转换:将字符串转为日期
*/
public class StringToDateConverter implements Converter<String, Date> {
/**
* 转换方法
* @param source 传进来的字符串
* @return
*/
public Date convert(String source) {
if (source == null){
throw new RuntimeException("请您输入日期");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
//将字符串转为日期
return df.parse(source);
} catch (Exception e) {
throw new RuntimeException("数据类型转换错误");
}
}
}
注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!--配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<bean class="cn.itcast.utils.StringToDateConverter"></bean>
</property>
</bean>
<!-- 开启SpringMVC框架注解的支持 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
如果想让输出符合我们的阅读习惯,可以修改User实体类
private Date birthday;
public String getFormattedBirthday() {
if (null != this.birthday){
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String birFormat = df.format(this.birthday);
return birFormat;
}
return null;
}
@Override
public String toString() {
return "User{" +
"uname='" + uname + '\'' +
", age=" + age +
", birthday=" + this.getFormattedBirthday() +
'}';
}
只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象
/**
* 测试原生Servlet API
* @return
*/
@RequestMapping("/testServlet")
public String testServlet(HttpServletRequest request, HttpServletResponse response){
System.out.println("执行了...");
System.out.println(request);
System.out.println(response);
HttpSession session = request.getSession();
System.out.println(session);
ServletContext servletContext = session.getServletContext();
System.out.println(servletContext);
return "success";
}
作用:把请求中的指定名称的参数传递给控制器中的形参。
位置:控制器方法的参数前面
属性
代码如下
/**
* 接收请求参数
* @RequestParam("name") 表示,请求参数中必须含有一个叫做name的属性,
* 并且将这个参数的值赋给username
* 注解加在哪个方法参数的前面,就表示给那个参数赋值
* 此时可以不用保证表单的name属性和方法参数的名称一致
* @param username
* @return
*/
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam("name") String username){
System.out.println("执行了....");
System.out.println(username);
return "success";
}
作用:用于获取请求体的内容(注意:get方法不可以使用。get方式把参数拼在地址栏了,所以没有请求体)
位置:控制器方法的参数前面
属性
代码如下
/**
* 获取请求体
* @param body
* @return
*/
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了....");
System.out.println(body);
return "success";
}
作用:用于绑定 url 中的占位符。例如:url中有/delete/{id},{id}就是占位符
位置:控制器方法的参数前面
属性
Restful风格的URL
含义:请求路径一样,可以根据不同的请求方式去执行后台的不同方法
用法:配置好每个方法使用什么请求方式:put、post或者get。然后发送请求的时候,使用路径+占位符(如果有的话)来指定让哪个方法执行
restful风格的URL优点
代码如下
控制器代码:
/**
* PathVariable注解
* @PathVariable("sid")能拿到传过来的sid,并给id赋值
* @param id
* @return
*/
@RequestMapping("/testPathVariable/{sid}")
public String testPathVariable(@PathVariable("sid") String id){
System.out.println("执行了....");
System.out.println(id);
return "success";
}
JSP代码:格式是路径/id
作用:获取指定请求头的值(不常用)
位置:控制器方法的参数前面
属性
value/name:请求头的名称
代码如下
/**
* 获取请求头
* @param header
* @return
*/
@RequestMapping("/testRequestHeader")
public String testRequestHeader(@RequestHeader(name = "Accept") String header){
System.out.println("执行了....");
System.out.println(header);
return "success";
}
作用:用于获取指定cookie的名称的值(不常用)
位置:控制器方法的参数前面
属性
value:cookie的名称
代码
/**
* CookieValue注解
* @param cookieValue
* @return
*/
@RequestMapping("/testCookieValue")
public String testCookieValue(@CookieValue("JSESSIONID") String cookieValue){
System.out.println("执行了....");
System.out.println(cookieValue);
return "success";
}
作用
应用场景
具体的代码
1. 修饰的方法有返回值
````java
/**
* 作用在方法,该方法会先执行
* 有返回值。会返回给控制器方法
* @param uname
* @return
*/
@ModelAttribute
public User showUser(String uname){
System.out.println("showUser()方法执行了...");
//通过用户名查询数据库(模拟)
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setBirthday(new Date());
return user;
}
/**
* 修改用户的方法
* @param user
* @return
*/
@RequestMapping("/updateUser")
public String updateUser(User user){
System.out.println("updateUser方法执行了....");
System.out.println(user);
return "success";
}
````
修饰的方法没有返回值
/**
* 作用在方法,该方法会先执行
* 查询数据库后将user存入map集合
*/
@ModelAttribute
public void showUser(String uname, Map<String,User> map){
System.out.println("showUser()方法执行了...");
//通过用户名查询数据库(模拟)
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setBirthday(new Date());
System.out.println(user);
map.put("abc", user);
}
/**
* 修改用户的方法
* 使用@ModelAttribute注解,根据key获取value,并赋给user
* @param user
* @return
*/
@RequestMapping("/updateUser")
public String updateUser(@ModelAttribute("abc") User user){
System.out.println("updateUser方法执行了....");
System.out.println(user);
return "success";
}
作用:用于多次执行控制器方法间的参数共享
位置:类上面
属性
代码如下
@Controller
@RequestMapping("/anno")
@SessionAttributes(value = {
"msg"},types = {
String.class}) //将数据存入session域对象中
public class AnnoController {
/**
* 将数据存入到request域对象中
* 再由类上方的@SessionAttributes注解存入到session域对象中
* @param model 接口
* @return
*/
@RequestMapping("/saveSessionAttributes")
public String saveSessionAttributes(Model model){
System.out.println("saveSessionAttributes方法执行了....");
//底层会存到request域对象中
model.addAttribute("msg", "大佬");
return "success";
}
/**
* 从session域中取数据
* @param modelMap
* @return
*/
@RequestMapping("/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
System.out.println("getSessionAttributes方法执行了....");
String msg = (String) modelMap.get("msg");
System.out.println(msg);
return "success";
}
/**
* 清除session域的数据
* @param status
* @return
*/
@RequestMapping("/delSessionAttributes")
public String delSessionAttributes(SessionStatus status){
System.out.println("delSessionAttributes方法执行了....");
//清除数据
status.setComplete();
return "success";
}
}
SpringMVC的概述
入门
参数绑定
常用注解