servlet
阅读资料JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)
什么是servlet
Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
Servlet的工作模式
- 客户端发送请求至服务器
- 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器
- 服务器将响应返回客户端
-
快速入门
@WebServlet(urlPatterns=“/demo1”)
生命周期
init()
service()
destroy()
方法介绍
体系结构
urlPattern配置
XML编写servlet
Request&Response
HTTP-请求数据格式
例子
request继承体系
Request获取请求数据
request通用方式获取请求参数
request请求转发
Filter
SpringMVC
简介
入门案例
步骤
1.配置pom.xml,导入依赖坐标和tomcat插件
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>springmvc_01_quickstart</finalName>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
2.定义controller
//2.定义controller
//2.1使用@Controller定义bean
@Controller
public class UserController {
//2.2设置当前操作的访问路径
@RequestMapping("/save")
//2.3设置当前操作的返回值类型
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'module':'springmvc'}";
}
}
3.创建SpringMvcConfig配置类
//3.创建springmvc的配置文件,加载controller对应的bean
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
4.定义一个servlet容器启动的配置类,在里面加载spring的配置
//4.定义一个servlet容器启动的配置类,在里面加载spring的配置
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//加载springMVC容器配置。
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置哪些请求归属springMVC处理。设定SpringMVC对应的servlet映射路径
@Override
protected String[] getServletMappings() {
//设置为"/"表示拦截所有请求,让任意请求都归springMVC处理
return new String[]{"/"};
}
//如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
5.启动运行项目,浏览器访问
注解介绍
@Controller
@RequestMapping
@ResponseBody
开发总结
入门案例工作流程分析
Controller加载控制与业务bean加载控制
如何让SpringConfig加载bean时排除springMVC相关bean(表现层bean)呢?
方式一
@Configuration
@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}
方式二
@Configuration
@ComponentScan(value="",
excludeFilters=@ComponentScan.Filter(
type = FilterType.ANNOTATION, //通过注解方式排除
classes = Controller.class //排除@Controller注解
)
)
public class SpringConfig {
}
- excludeFilters属性:设置扫描加载bean时,排除的过滤规则
- type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
- ANNOTATION:按照注解排除
- ASSIGNABLE_TYPE:按照指定的类型过滤
- ASPECTJ:按照Aspectj表达式排除,基本上不会用
- REGEX:按照正则表达式排除
- CUSTOM:按照自定义规则排除
- classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
方式三
利用Spring提供的一种更简单的配置方式去创建AnnotationConfigWebApplicationContext对象
public class ServletContainersInitConfig extends
AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
PostMan插件
设置请求映射路径
按照规范,在控制器类上定义整个模块的请求路径的前缀
请求与相应
请求
1. get请求和post请求发送普通参数
GET请求
//2.定义controller
//2.1使用@Controller定义bean
@Controller
@RequestMapping("/user")
public class UserController {
//2.2设置当前操作的访问路径
@RequestMapping("/commonParam")
//2.3设置当前操作的返回值类型
@ResponseBody
public String commonParam(String name, int age, String addr){
System.out.println("普通参数传递 name ==>"+ name);
System.out.println("普通参数传递 age ==>"+ age);
System.out.println("普通参数传递 addr ==>"+ addr);
return "{'module':'common param'}";
}
}
使用postman发送get请求,发送成功
POST请求
SpringMVC添加过滤器来处理中文乱码问题
public class ServletContainersInitConfig extends
AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
//乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
2. 5种类型参数传递
普通参数
前端给的请求参数是name ,后台的形参是userName ,两个名称对不上的解决方法:
- 使用**@RequestParam(“请求参数名”)**注解
- 发送请求与参数:http://localhost/commonParamDifferentName?name=张三&age=18
- 后台接收参数:
@RequestMapping("/commonParamDifferentName")
@ResponseBody
public String commonParamDifferentName(@RequestParam("name") String
userName , int age){
System.out.println("普通参数传递 userName ==> "+userName);
System.out.println("普通参数传递 age ==> "+age);
return "{'module':'common param different name'}";
}
POJO类型参数
此时需要使用前面准备好的POJO类,先来看下User
public class User {
private String name;
private int age;
//setter...getter...toString略
}
发送请求和参数:
后台接收参数:
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递 user ==> "+user);
return "{'module':'pojoParam'}";
//请求参数key的名称要和POJO中属性的名称一致,否则无法封装。
}
POJO嵌套参数
Address嵌套在User中
public class User {
private String name;
private int age;
private Address address;
public Address getAddress() {
return address;
}
//setter...getter...toString
}
发送请求和参数:
如何给实体类中的某个对象传属性值?
对象.属性
后台接收参数:
//pojo嵌套参数
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
System.out.println("普通参数传递 user ==>"+ user);
return "{'module':'pojoContainPojoParam'}";
}
数组类型参数
后台接收参数:
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("数组参数传递 likes ==> "+ Arrays.toString(likes));
return "{'module':'array param'}";
}
集合类型参数
后台接收参数:
//集合参数:同名请求参数可以使用**@RequestParam**注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
//如果没有@RequestParam则会报错,因为SpringMVC将List看做是一个POJO对象来处理,将其创建一个对象并准备把前端的数
//据封装到对象中,但是List是一个接口无法创建对象,所以报错
System.out.println("集合参数传递 likes ==> "+ likes);
return "{'module':'list param'}";
}
3. json数据传递参数
准备工作
1.添加依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
2.开启SpringMVC注解支持
@Configuration
@ComponentScan("controller")
//开启json数据类型自动转换
@EnableWebMvc
public class SpringMvcConfig {
}
3.如何用postman发送json格式的数据
json数组
参数前添加**@RequestBody**
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)参数传递 likes ==> "+ likes);
return "{'module':'list param For Json param'}";
}
json对象(POJO)
- 请求和数据的发送:
{
"name":"itcast",
"age":15,
"address":{
"province":"beijing",
"city":"beijing"
}
}
- 后端接收数据:
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
System.out.println("pojo(json)参数传递 user ==> "+user);
return "{'module':'pojo for json param'}";
}
json数组(POJO)
请求和数据的发送:
[
{"name":"itcast","age":15},
{"name":"itheima","age":12}
]
后端接收数据:
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
System.out.println("list pojo(json)参数传递 list ==> "+list);
return "{'module':'list pojo for json param'}";
}
注解介绍
@EnableWebMvc
@RequestBody
@RequestBody与@RequestParam区别
4.日期类型参数传递
- 做好准备工作(同上)
- 发送请求:
http://localhost/dataParam?date=2088/08/08&date1=2088-08-08&date2=2088/08/08 8:08:08
- 接受请求
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
@DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
//使用@DateTimeFormat进行格式转换
@DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date
date2)
System.out.println("参数传递 date ==> "+date);
System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);
System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
return "{'module':'data param'}";
}
Convert接口,类型转换器
响应
- 准备工作:添加依赖,以下为需新添加的依赖
- 发送请求:此处不涉及到页面跳转,因为我们现在发送的是post请求,使用PostMan进行 测试,输入地址http://localhost/…访问
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
1.响应页面
1.设置返回页面
@Controller
public class UserController {
@RequestMapping("/toJumpPage")
//注意
//1.此处不能添加@ResponseBody,如果加了该注入,会直接将page.jsp当字符串返回前端
//2.方法需要返回String
public String toJumpPage(){
System.out.println("跳转页面");
return "page.jsp";
}
}
2.运行测试
2.响应数据
1.文本数据
@Controller
public class UserController {
@RequestMapping("/toText")
//注意此处该注解就不能省略,如果省略了,会把response text当前页面名称去查找,如果没有
回报404错误
@ResponseBody
public String toText(){
System.out.println("返回纯文本数据");
return "response text";
}
}
2.json数据
响应POJO对象
@Controller
public class UserController {
@RequestMapping("/toJsonPOJO")
@ResponseBody//注意添加该注解
public User toJsonPOJO(){
System.out.println("返回json对象数据");
User user = new User();
user.setName("itcast");
user.setAge(15);
return user;
}
}
注解介绍
HttpMessageConverter接口
REST风格
-
传统方式一般是一个请求url对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了你的请求url地址,就大概知道该url实现的是一个什么样的操作。
查看REST风格的描述,你会发现请求地址变的简单了,并且光看请求URL并不是很能猜出来该URL的具体功能 -
问题:如何区分调用了哪个请求?
按照REST风格访问资源时使用行为动作区分对资源进行了何种操作
http://localhost/users 查询全部用户信息 GET (查询)
http://localhost/users/1 查询指定用户信息 GET (查询)
http://localhost/users 添加用户信息 POST (新增/保存)
http://localhost/users 修改用户信息 PUT (修改/更新)
http://localhost/users/1 删除用户信息 DELETE (删除)
HTTP请求方法
RESTful入门案例
设定http请求动作(动词)
method = RequestMethod.
根据对资源进行何种操作来修改method
@RequestMapping(value = "/books/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){//id要与上列大括号中/{id}相对应
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
2.传递路径参数
修改@RequestMapping的value属性,将其中修改为/users/{id},目的是和路径匹配
方法:在方法的形参前添加@PathVariable注解
RESTful快速开发
- 问题1:每个方法的@RequestMapping注解中都定义了访问路径/books,重复性太高。
- 问题2:每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高。
- 问题3:每个方法响应json都需要加上@ResponseBody注解,重复性太高。
解决方法:
- 将@RequestMapping提到类上面,用来定义所有方法共同的访问路径。
- 使用@GetMapping @PostMapping @PutMapping @DeleteMapping代替
如:
//@RequestMapping(value = "/{id}",method = RequestMethod.GET)
@GetMapping("/{id}")
3.将ResponseBody提到类上面,让所有的方法都有@ResponseBody的功能,使用 @RestController注解替换@Controller与@ResponseBody注解,简化书写
@RestController //@Controller + ReponseBody
最终效果:
@RestController //@Controller + ReponseBody
@RequestMapping("/books")
public class BookController {
//@RequestMapping(method = RequestMethod.POST)
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
//@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
}
SSM整合
整合配置
模块结构
导入maven依赖坐标
<dependencies>
<!--junit4-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--日志-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- mysql数据库驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
<!--druid数据库连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<!-- Mybatis框架:-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<!-- MyBatis整合Spring的适配包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--EL表达式-->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--json jar包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.5</version>
</dependency>
<!-- Spring依赖 -->
<!--1. Spring核心依赖,上面已经有日志了 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!--spring的aop jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!--这两个jar包是阿帕奇的-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--2. SpringDAO层依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!--3. Spring WEB依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!--4.Spring-test相关依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
</dependencies>
config类包
JdbcConfig
package com.itheima.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import javax.sql.DataSource;
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setPassword(password);
dataSource.setUrl(url);
dataSource.setDriverClassName(driver);
dataSource.setUsername(username);
return dataSource;
}
}
MyBatisConfig
package com.itheima.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class MyBatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setTypeAliasesPackage("com.itheima.domain");
return factoryBean;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.dao");
return msc;
}
}
ServletConfig
package com.itheima.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
SpringConfig
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
@Configuration
@ComponentScan({"com.itheima.service"})
@PropertySource({"jdbc.properties"})
@Import({JdbcConfig.class, MyBatisConfig.class})
public class SpringConfig {
}
SpringMvcConfig
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
表现层与前端数据传输协议定义
异常处理器