一、Servlet
二、HTTP
三、HttpServlet
见晨考
javaweb开发,就是需要服务器
接收前端发送的请求
,以及请求中的数据,经过处理(jdbc操作),然后向浏览器做出响应
.
我们要想在服务器中写java代码来接收请求,做出响应,我们的java代码就得遵循tomcat开发规范
因此Tomcat提供了开发的规范,就是servlet.
Servlet就是运行在服务器上的程序,可交互式的接收服务器的请求,并可以做出响应
总结Servlet的作用:
- 运行在服务器,是一个服务器端的程序
- 接收客户端请求,向客户端做出响应
- 动态网页(jsp)
手动补全目录结构
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.qfgroupId>
<artifactId>day46_servletartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>javax.servlet.jsp-apiartifactId>
<version>2.3.1version>
dependency>
dependencies>
project>
- 实现javax.servlet.Servlet接口
- 重写方法
- 在核心方法service()里面完成接收请求,做出响应
package com.qf.servlet;
import javax.servlet.*;
import java.io.IOException;
public class MyServlet1 implements Servlet {
@Override
public void init(ServletConfig config) throws ServletException {}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 核心方法,服务,在这个方法中可以完成接收请求,做出响应
* @param req 用来处理请求的对象
* @param res 用来处理响应的对象
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
// 通过请求对象,可以获得请求的ip
String ip = req.getRemoteAddr( );
System.out.println("ip = "+ip );
// 响应
// res.getWriter()获得字符输出流
// .writer() 写出到浏览器字符(中文可能乱码)
res.getWriter().write("i'm Response,Hello");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {}
}
因为服务器中会有很多servlet,浏览器发请求如何确定访问哪一个servlet类?
此时就需要做一个映射: 请求路径和servlet类的映射,即发出的请求由哪个servlet类来处理
配置需要写在webapp/WEB-INF/web.xml中
<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_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>servlet1servlet-name>
<servlet-class>com.qf.servlet.MyServlet1servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>/s1url-pattern>
servlet-mapping>
web-app>
浏览器发出请求,经过web.xml中配置的信息,
- 匹配url-pattern>/s1
- 通过servlet-name找到servlet类
- 再通过servlet-class,找到servlet类路径
- 该servlet就可以执行service()
web项目已经开发完毕,将项目部署到服务器Tomcat
配置Tomcat
部署项目
启动项目
访问发出请求
http://localhost:8080/day46/s1
-Dfile.encoding=utf-8
package com.qf.util;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class DBUtil {
// 创建Properties类对象,专用于操作properties文件
private static final Properties properties = new Properties( ); // 声明Druid连接池的连接池对象
// 数据连接,一般称作数据源
dataSource private static DruidDataSource dataSource;
static {
try {
InputStream inputStream = DBUtil.class.getResourceAsStream("/jdbc.properties"); properties.load(inputStream); // 不需要由我们加载驱动 // 需要给dataSource赋值
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { System.out.println("加载驱动异常!!"); e.printStackTrace( ); } }
public static Connection getConnection() {
Connection conn = null;
try { // 不需要我们获得连接
// 而是通过Druid获得
conn = dataSource.getConnection( );
} catch (Exception e) {
System.out.println("获得连接出异常!!!"); e.printStackTrace( );
}
return conn;
}
/** * 关闭所有流 */
public static void closeAll(Connection conn, Statement s) {
if (conn != null) {
try {
conn.close( );
} catch (SQLException throwables) { throwables.printStackTrace( );
}
}
if (s != null) {
try {
s.close( );
} catch (SQLException throwables) {
throwables.printStackTrace( );
}
}
}
public static void closeAll(Connectionconn, Statement s, ResultSet rs) {
if (conn != null) {
try {
conn.close( );
} catch (SQLException
throwables) {
throwables.printStackTrace(
);
}
}
if (s != null) {
try {
s.close( );
} catch (SQLException throwables) {
throwables.printStackTrace( );
}
}
if (rs != null) {
try {
rs.close( );
} catch (SQLException throwables) {
throwables.printStackTrace( );
}
}
}
/** * 封装查询方法,返回一个对象 * 参数1 执行查询的SQL,预处理的,条件用?占位 * select * from tb_user where id = ? and username = ? and password = ? * 参数2 结果要封装的类 * 参数3 给?赋值,不定长参数,是数组 * 1,admin,123456 */
public static <T> T selectOne(String sql, Class<T> t, Object... args) {
Connection conn = getConnection( ); PreparedStatement ps = null;
ResultSet rs = null;
T target = null;
try {
ps = conn.prepareStatement(sql); for (int i = 0; args != null && i < args.length; i++) { ps.setObject(i + 1, args[i]); }
rs = ps.executeQuery( );
/** * 创建对象 * 从数据库取出数据,并设置对象属性 */
while (rs.next( )) {
target = t.newInstance( );
Field[] declaredFields =t.getDeclaredFields( ); for (int i = 0; i < declaredFields.length; i++) { Field field = declaredFields[i];
Object value = rs.getObject(field.getName( ));
// 破解私有
field.setAccessible(true);
// 给对象的该字段赋值
field.set(target, value);
}
}
} catch (Exception e) {
e.printStackTrace( );
} finally { closeAll(conn, ps, rs); } return target; } public static <T> List<T> selectAll(String sql, Class<T> t, Object... args) { Connection conn = getConnection( ); PreparedStatement ps = null; ResultSet rs = null; T target = null; ArrayList<T> list = new ArrayList<>( ); try { ps = conn.prepareStatement(sql); for (int i = 0; args != null && i < args.length; i++) { ps.setObject(i + 1, args[i]); } rs = ps.executeQuery( ); /** * 创建对象 * 从数据库取出数据,并设置对象属性 */ while (rs.next( )) { target = t.newInstance( ); Field[] declaredFields = t.getDeclaredFields( ); for (int i = 0; i < declaredFields.length; i++) { Field field = declaredFields[i]; Object value = rs.getObject(field.getName( )); // 破解私有
field.setAccessible(true); // 给对象的该字段赋值
field.set(target, value); } list.add(target); } } catch (Exception e) { e.printStackTrace( ); } finally { closeAll(conn, ps, rs); } return list; } /** * 增删改方法一样 */ public static boolean update(String sql, Object... args) { Connection conn = getConnection( ); PreparedStatement ps = null; int num = 0; try { ps = conn.prepareStatement(sql); for (int i = 0; args != null && i < args.length; i++) { ps.setObject(i + 1, args[i]); } num = ps.executeUpdate( ); } catch (Exception e) { e.printStackTrace( ); } finally { closeAll(conn, ps); } return num > 0 ? true : false; }}
如果启动失败,要及时查看控制台日志
立即加载解析web.xml文件
1)服务器内就会知道当前服务器能接收哪些请求路径
2)也知道请求路径被哪个servlet处理
3)如果web.xml中有错,启动会失败,要及时查看控制台日志
4)常见的错误就是url-partten写错了
启动成功,跳转至index.jsp页面(如果没有该页面,报错404)
浏览器发出请求
1)发出请求路径,根据ip找到服务器,再根据8080找到服务器中的程序htttp://localhost:8080
2)然后再通过名字找到服务器中的项目,默认访问首页(index.jsp),找不到报错404
htttp://localhost:8080/day46
3)然后发出具体的请求路径 http://localhost:8080/day46/a
发出的请求会经过web.xml中配置的路径去匹配
1)web.xml中没有匹配到路径,报错404
2)web.xml中有匹配的路径,就找对应的servlet让其执行
servlet执行service()方法,完成接收请求,和做出响应的动作
如果后台出问题,主要是指java代码报错,页面会报错500
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>s1url-pattern>
servlet-mapping>
Caused by: java.lang.IllegalArgumentException: Invalid <url-pattern> s1 in servlet mapping
项目启动,默认访问
webapp
/index.jsp页面没有该页面,启动报404
也可以通过web.xml文件来修改默认启动访问页面
<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_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>login.htmlwelcome-file>
welcome-file-list>
web-app>
现在的访问路径是
http://localhost:8080/day46/
这个访问路径,是在配置Tomcat时给设置的
再访问就是http://localhost:8080/java2217
有些web.xml上方的约束文件不同,即web.xml内容的顺序不同.如果有报错,鼠标悬浮查看错误信息,就会发现,标签有顺序要求!! 顺序如下
映射细节就是浏览器发出请求,访问servlet时的一些操作
第一种: 固定路径
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>/s1url-pattern>
servlet-mapping>
第二种: 模糊匹配路径
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
第三种: 多层路径
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>/a/*url-pattern>
servlet-mapping>
第四种: 后缀匹配
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
一个Servlet可以处理多个请求
多个映射路径映射
可以
到同一个Servlet,比如设置url-partten为/*,那么就可以任何请求都就可以找到MyServlet1执行
也可以这么设置,让/s1 /s11 /s111都可以访问到MyServlet1
servlet-mapping> <servlet-name>servlet1servlet-name> <url-pattern>/s1url-pattern> <url-pattern>/s11url-pattern> <url-pattern>/s111url-pattern> servlet-mapping>
或者这么写
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>s1url-pattern>
servlet-mapping>
<servlet-mapping>
<servlet-name>servlet1servlet-name>
<url-pattern>s2url-pattern>
servlet-mapping>
一个请求不能到多个Servlet!!! 不能这样配置!!!
- 创建
请求到达该Servlet时才创建
且只创建一次,单例对象
- 初始化
- 创建完对象,立即初始化
- 也就初始化一次
- 服务
- 请求到达该类,对象创建完毕,初始化完毕后就执行service干活
- 后续,
每次请求到达该类,service()都会执行
- 死亡
- 服务器关闭时销毁
浏览器和服务器之间是通过http协议在传输数据.
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于
请求与响应模式
的、无状态的、应用层的协议,运行于TCP协议基础之上。
课下查询书籍<<网络通信>> <<计算机组成原理>>
通过浏览器的开发者工具(F12)监听任何一个网站的请求响应过程,就可以看到请求报文和响应报文
请求行内有请求方式(GET),和请求路径(/s?wd=java)
ps: 后续就可以通过servlet获得这些数据
响应行中有协议(http/1.1) ,响应状态码(200) ,响应信息(OK)
HTTP中常见的请求方式
- get
- post
GET请求
- 数据会通过浏览器地址栏发送
- 数据量大小有限制,最多4kb
- 请求数据不安全
- 效率相对较高
开发中建议,通过服务器查询数据使用get请求,比如findOne,findAll等信息
前端技术中,如何发送一个get请求?
POST请求
- 数据是隐藏的,在地址栏看不见,但是是在请求体中
- 数据量大小不限
- 数据相对安全
- 效率相对较低
开发中建议,使用POST向服务器发送数据,登录,注册,更新,上传文件等
前端技术中,如何发送一个POST请求?
之前Servlet程序,需要实现Servlet接口,有不好之处
- 实现接口,重写所有方法,但是只关心如何接收请求和做出响应
- service()方法可以处理各种各样的请求,不够专一
基于以上问题,服务器就提供一个专业用于处理HTTP请求和响应的一个Servlet类,HttpServlet,该类是抽象类,内部提供一些方法,供选择重写
- 浏览器发出get请求,那么就重写doGet方法处理get请求
- 浏览器发出post请求,那么就重写doPost方法处理post请求
package com.qf.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet3 extends HttpServlet {
/**
* 重写doGet,处理get请求
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("接收get请求" );
}
/**
* 重写doPost,处理post请求
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("接收post请求" );
}
}
<servlet>
<servlet-name>servlet3servlet-name>
<servlet-class>com.qf.servlet.MyServlet3servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servlet3servlet-name>
<url-pattern>/s3url-pattern>
servlet-mapping>
<form action="/day46/s3" method="post">
<input type="submit" value="登录post">
form>
<hr>
<form action="/day46/s3" method="get">
<input type="submit" value="登录get">
作业/总结/掌握
1 整个创建配置部署启动servlet过程
2 理解执行流程
3 画出javaweb开发图
4 前端如何发送请求?
5 前端的请求方法有哪些?
6 后台有哪些处理不同请求方式的方法?
doGet
doPost
7 前端请求通过什么和后台服务器关联?
web.xml配置映射路径
修改idea中java版本
Maven-POM文件中设置编译版本
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
plugins>
build>