💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
#### 1.Servlet开发入门 - ##### 1.1 Servlet由来 - 第一天我们就说过,需要服务器,使用Java代码,访问数据库。因此,我们需要书写java程序,去访问数据库,那么java程序在哪里运行? - 用户的请求从浏览器发出,由服务器接收,因此,用户需要什么服务器才知道由此可见,这些java程序必须安装到服务器中,让服务器调用执行。 - 那么我们可以随意写java程序码?不能,因为就像螺丝和螺帽一样,必须按照一定大小尺寸规定,生成,后期才可以匹配使用。 - 因此sun公司为了让程序员书写的java程序可以严丝合缝的安装到服务器中,定义了一个接口Servlet - ##### 1.2 Servlet介绍 - servlet是运行在Web服务器中的小型java程序,servlet通常通过HTTP(超文本传输协议)接收和响应来自Web客户端的请求。 - 要实现此接口,可以编写一个扩展javax.servlet.http.HttpServlet的HTTP servlet - servlet生命周期方法的调用顺序 - 1.构造servlet,然后使用init方法将其初始化 - 2.处理来自客户端的对servlce方法的所有调用 - 3.从服务中取出servlet,然后使用destroy方法销毁它,最后进行垃圾回收并中止它。 - 什么是servlet? - 处理请求和响应请求的java程序 - 怎么创建servlet? - 继承HttpServlet类,在web.xml中配置,servlet 3.0版本之后不需要在web.xml中配置 #### 2.Servlet开发的步骤 - ##### 2.1 在cn.igeek.web包下 创建一个类 实现 HttpServlet 类 ``` package cn.yiran.web.servlet; import javax.servlet.http.HttpServlet; public class ServletDemo extends HttpServlet { } ``` - ##### 2.2 重写doGet和doPost,init()方法 ``` package cn.yiran.web.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo extends HttpServlet { @Override public void init(ServletConfig config) throws ServletException{ System.out.println("init()...."); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet...."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doPost...."); } } ``` - ##### 2.3 在当前项目中的web.xml文件中配置当前开发好的Servlet程序 ``` <!-- servlet路径 --> <servlet> <!-- servlet的名称 --> <servlet-name>ServletDemo</servlet-name> <!-- servlet的具体实现类 --> <servlet-class>cn.yiran.web.servlet.ServletDemo</servlet-class> </servlet> <!-- servlet映射 --> <servlet-mapping> <!-- servlet的名称 --> <servlet-name>ServletDemo</servlet-name> <!-- 访问这个servlet程序的请求路径 --> <!-- 可以定义多个Servlet,这里配置请求路径为,所有的servlet --> <url-pattern>/ServletDemo</url-pattern> </servlet-mapping> ``` - ##### 2.4 发布这个项目,运行服务器,测试 - 直接在网页链接后面输入servlet类名即可,如:http://localhost:8080/web/ServletDemo - 在Tomcat server信息中查看调用方法为:init()... Get()... #### 3.Servlet中的细节 - ##### 3.1 http://localhost:8080/web/ServletDemo - http:// --> 协议 - localhost --> 电脑 - 8080 --> 服务器 - web --> web目录 - ServletDemo --> web.xml中的/ServletDemo --> 所有的ServletDemo类 --> 某个ServletDemo类 --> init()方法+doGet()方法 - 总结:通过请求路径,查询web.xml中servlet配置,获取当前servlet对象,调用java程序。 #### 4.使用IDEA模版开发Servlet(重点):可以更快捷的创建servlet对象 - ##### 4.1 如何直接创建servlet对象 - 选中包名 --> New --> servlet - Create Java EE 6 annotated class ,创建Java EE 6 注解类,servlet3.0之后,可以利用注解来配置servlet,而不需要在web.xml中配置 - 会自动创建doGet和doPost方法 #### 5.servlet3.0注解 - ##### 5.1 @WebListener注解 - 表示在web.xml中配置的 ``` <listener> <listener-class>ListenerClass</listener-class> </listener> ``` - ##### 5.2 @WebFilter - 这个注解就是表示的拦截器 - 注解的主要参数及其含义 ![image](https://images2015.cnblogs.com/blog/593110/201611/593110-20161123225559315-2079803493.png) - ##### 5.3 @WebServlet - 这个注解表示的就是一般的Servlet - 注解的主要参数及其含义,参数和Filter差不多 ![image](https://images2015.cnblogs.com/blog/593110/201611/593110-20161123230047534-1707818143.png) - ##### 5.4 @WebInitParam - 表示的就是参数,相当于<init-param> - 注解的主要参数及其含义 ![image](https://images2015.cnblogs.com/blog/593110/201611/593110-20161123230313425-824229219.png) - ##### 5.5 @MultipartConfig - 该注解主要是为了辅助 Servlet 3.0 中 HttpServletRequest 提供的对上传文件的支持。 - 该注解标注在 Servlet 上面,以表示该 Servlet 希望处理的请求的 MIME 类型是 multipart/form-data。 - 另外,它还提供了若干属性用于简化对上传文件的处理。具体如下 ![image](https://images2015.cnblogs.com/blog/593110/201611/593110-20161123231817503-47345623.png) #### 6.获取请求 - ##### 6.1 准备html - 在web目录下新建一个regist.jsp ``` <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>注册</title> </head> <body> <form action="MyServlet" method="post"> 用户名:<input type="text" name="username" /><br /> 爱 好:<input type="checkbox" name="hobby" value="football" />足球 <input type="checkbox" name="hobby" value="basketball" />篮球<br /> <input type="submit" value="提交" /> </form> </body> </html> ``` - ##### 6.2 完善MyServlet方法 - 给@WebServlet加上value属性 --> value = "/MyServlet" - 完善doPost方法 - 服务器给我们提供了一个Request对象,为HTTP servlet 提供请求信息 - getParameter(String name) - 返回类型 --> String - 根据name 获取对应的值 - getParameterMap() - 返回类型 --> Map - 将请求信息中,参数名作为key,参数值作为value,封装到map中 - getParameterValues(String name) - 返回类型 --> String[] - 获取name相同的所有value 例如复选框 ``` package cn.yiran.web.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "MyServlet",value = "/MyServlet") public class MyServlet extends HttpServlet { @Override public void init() throws ServletException { super.init(); System.out.println("3.0 init()"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("3.0 doPost"); // getParameter(name) --> 根据name属性获取值 String username = request.getParameter("username"); System.out.println("username:"+username); // getParameterValues(name) --> 根据name属性获取多个值,得到的是一个String数组 String[] hobby = request.getParameterValues("hobby"); for (String str:hobby){ System.out.println("hobby:"+str); } } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } } ``` - ##### 6.3 测试控制台是否能输出 - 注意:在输入框中输入中文,读取出来输出为? 这是因为没有设置字符的编码格式 - request.setCharacterEncoding("utf-8") --> 设置接收数据的字符编码格式为utf-8 - response.setCharacterEncoding("utf-8"),同理。一般设置字符集,位于方法的最前。 - response.setContentType("text/html; charset=utf-8"); --> 设置返回内容类型 #### 7.发送响应 - ##### 7.1 发送响应的对象Response对象 - 提供特定于HTTP的发送响应功能。 - servlet容器创建HttpServletResPonse对象,并将该对象作为参数传递给servlet的service方法(doGet,doPost,等等,这些都属于service方法) - ##### 7.2 Response方法 - getWriter() - 返回 --> java.io.PrintWriter - 返回可将字符文本发送到客户端的 PrintWriter 对象 - PrintWriter对象 - 继承于 --> java.io.Writer - 方法 --> writer(String s) --> 写入字符串 - ##### 7.3 发送响应 - 直接在service(服务)方法中调用Response对象使用方法即可 ``` System.out.println("========发出响应==========="); response.getWriter().write("test OK!!!!"); ``` #### 8.Servlet开发应用——登录案例 - ##### 8.1 准备数据表 - 需要3个字段,id、username、password ``` create database JavaEE charset=utf8; use javaee create table user( id int auto_increment primary key not null, username varchar(20) not null, password varchar(20) not null ); insert into user(username,password) value('yiran','yiran'),('chunjue','chunjue'),('miku','miku'); ``` - ##### 8.2 导入jar包 - c3p0-0.9.1.2.jar - commons-dbutils-1.6.jar - mysql-connector-java-5.0.8-bin.jar - ##### 8.3 新建包结构 - src - cn.yiran.web - dao --> 数据访问对象,实现对数据库表user的增删改查 - UserDAO - domain --> 实体层,javabean,mvc中的modle - User - service --> 业务逻辑层 - UserService - servlet --> 控制器,接收和返回结果 - LoginServlet - utils --> 工具层 - JDBCUtils - c3p0-config-xml --> c3p0连接池的配置文件 - ##### 8.4 dao层 -- UserDAO ``` package cn.yiran.web.dao; import cn.yiran.web.domain.User; import cn.yiran.web.utils.JDBCUtils; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import java.sql.SQLException; /** * 数据访问对象,实现对数据库表user的增删改查 * */ public class UserDAO { private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource()); // 定义一个实现登录的方法 public User login(User user){ String sql = "select * from user where username=? and password=?"; try{ return qr.query(sql,new BeanHandler<User>(User.class),user.getUsername(),user.getPassword()); } catch (SQLException e){ e.printStackTrace(); throw new RuntimeException("登录失败"); } } } ``` - ##### 8.5 damain层 -- User ``` package cn.yiran.web.domain; public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + "]"; } } ``` - ##### 8.6 service层 -- UserService ``` package cn.yiran.web.service; import cn.yiran.web.dao.UserDAO; import cn.yiran.web.domain.User; /** * 封装对用户进行操作的业务逻辑 * */ public class UserService { private UserDAO userDAO = new UserDAO(); // 实现用户登录的业务逻辑 public User login(User user){ return userDAO.login(user); } } ``` - ##### 8.7 servlet层 -- LoginServlet ``` package cn.yiran.web.servlet; import cn.yiran.web.domain.User; import cn.yiran.web.service.UserService; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "LoginServlet",value = "/LoginServlet") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html; charset=utf-8"); // 1.获取请求页面中的数据 String username = request.getParameter("username"); String password = request.getParameter("password"); // 2.将获取的数据进行封装 User user = new User(); user.setUsername(username); user.setPassword(password); // 3.进行用户登录业务逻辑的判断 UserService userService = new UserService(); User loginUser = userService.login(user); // 4.判断返回值,做出响应 if (loginUser == null){ response.getWriter().write("账号或密码错误"); } else{ response.getWriter().write("登录成功"); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } ``` - ##### 8.8 utils -- JDBCUtils ``` package cn.yiran.web.utils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class JDBCUtils { // 创建c3p0的连接池 static ComboPooledDataSource cpds = new ComboPooledDataSource(); // 获得连接 public static Connection getConnection() throws Exception { // 获得连接 return cpds.getConnection(); } public static DataSource getDataSource() { return cpds; } // 释放资源 public static void release(Connection conn, Statement stmt, ResultSet rs) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } rs = null; release(conn, stmt); } // 释放资源 public static void release(Connection conn, Statement stmt) { try { if (stmt != null) { stmt.close(); } } catch (SQLException e) { e.printStackTrace(); } stmt = null; try { if (conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } conn = null; } } ``` - ##### 8.9 src层 -- c3p0-config.xml ``` <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://192.168.13.22:3306/javaee</property> <property name="user">root</property> <property name="password">root</property> </default-config> </c3p0-config> ``` - ##### 8.10 报错500 - 错误信息:java.lang.NoClassDefFoundError:org/apache/commons/dbutils/ResultSetHandler - 由于Tomcat没有找到jar包,自己放在lib中的jar包没有添加到项目资源中,项目依赖出了问题。需要在Artifacts点击fix,将lib包重新加载一次 - 解决教程:https://blog.csdn.net/silentkare/article/details/78160735o) #### 9.servlet生命周期 - ##### 9.1 生命周期图 - ![image](https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1531193504331&di=477bc7eabe67bde16fec4af18233fe78&imgtype=jpg&src=http%3A%2F%2Fimg4.imgtn.bdimg.com%2Fit%2Fu%3D124009709%2C4150369873%26fm%3D214%26gp%3D0.jpg) - 上图描述了servlet的生命周期。按照功能的不同,大致分为三个阶段,分别是 初始化阶段,运行阶段(最频繁) 和 销毁阶段。 注意:当服务器关闭的时候,项目中的servlet就调用第8步销毁。 - 总结:Servlet 的创建,在用户第一次请求,之后,创建。销毁,是发生在服务器关闭的时候。 - ##### 9.2 初始化阶段 - 当客户端向tomcat发送http请求访问servelt程序,tomcat首先会解析请求,检查内存中是否已经有了该servlet对象: - 如果有直接使用对应的servlet对象 - 如果没有就创建servlet实例对象,然后通过调用init()方法实现Servlet的初始化工作。 - 需要注意的是,在整个servlet的生命周期内,init方法只被调用了一次。除非配置发生改变。 - ##### 9.3 运行阶段 - 在这个阶段,tomcat服务器会为这个请求 创建 代表HTTP请求的ServletRequest对象 和 代表HTTP响应的 ServletResponse对象,然后将他们作为参数传递给service() 方法。 - servcie() 方法从ServletRequest对象获取请求的信息并做出处理;通过ServletResponse 对象生成响应的结果。 - 在servlet的整个生命周期内,对于servlet的每一次访问请求,tomcat都会调用servlet的service方法,并且创建新的ServletRequest对象和ServletResponse对象。也就是说service() 方法在servlet的生命周期内会被调用多次。 - ##### 9.4 销毁阶段 - 当服务器关闭时,servlet会随着Web应用的销毁而销毁 - 在销毁serlvet之前,tomcat会调用Servlet的destory方法,以便让Servlet对象释放他所占用的资源。 #### 10.路径书写问题 - 在学习Servlet的时候,每个Servlet程序都需要在当前的这个项目的web.xml文件中注册和映射。 - 在映射中书写的url-pattern标签的书写方式: - ##### 10.1 全路径匹配 - 在书写url-pattern的时候,必须以/开始,后面书写具体浏览器访问时的路径。 - 配置:<url-pattern>/DemoServlet</url-pattern> - 外界的访问方式: - http://localhost:8080/web/DemoServlet - ##### 10.2 路径通配符匹配 - 在书写url-pattern 的时候,以/开始,后面可以使用*号表示任意的匹配 - 配置:<url-pattern>/DemoServlet/*</url-pattern> - 外界在访问的时候,只要能够和/demo2匹配上,后面写任何东西都可以: - http://localhost:9090/test/DemoServlet/11111/aaa - ##### 10.3 扩展名匹配 - 在书写url-pattern 的时候,不能以/开始,以*开始,后面书写扩展名 - 配置: <url-pattern>*.do</url-pattern> - 常见的扩展名书写: - *.action &nbsp; *.do &nbsp; *.go - 访问的方式: - http://localhost:9090/test/xxxx.do - ##### 10.4 优先级 - url-pattern标签中的路径可以按照上述的三种书写,它们的优先级: - 全路径匹配 > 路径通配符匹配 > 扩展名匹配