
JavaWeb开发入门
Servlet
Servlet是Java Web开发的基石,与平台无关的服务器组件,它是运行在Servlet容器/Web应用服务器/Tomcat,负责与客户端进行通信
Servlet的功能:
创建并返回基于客户请求的动态HTML页面
与数据库进行通信
如何使用Servlet?
package cn.soutwind.servlet;
import javax.servlet.*;
import java.io.IOException;
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
String id = servletRequest.getParameter("id");
System.out.println("我是Servlet,我已接收到客户端传来的数据,参数为:" + id);
servletResponse.setContentType("text/html;charset=UTF-8");
servletResponse.getWriter().write("软件测试测试测试");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
浏览器不能直接访问Servlet文件,只能通过映射的方式来间接的访问Servlet,映射需要开发者手动配置,有两种配置方式。
基于XML文件的配置方式
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>cn.soutwind.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>
基于注解的方式:
@WebServlet("/demo01")
public class MyServlet implements Servlet {
}
上述两种配置方式结果完全一致,将demo01与MyServlet进行映射,即在浏览器地址栏直接访问demo01就可以映射到MyServlet
Servlet生命周期
当浏览器访问Servlet的时候,Tomcat会查询当前Servlet的实例化对象是否存在,如果不存在,则通过反射机制动态创建对象,如果存在,直接执行第三步
调用init方法完成初始化
调用Service方法完成业务逻辑操作
关闭Tomcat时,会调用destory方法,释放当前对象所占用的资源
Servlet的生命周期方法:无参构造方法、init、service、destory
无参构造方法值调用一次,创建对象。
init只调用一次,初始化对象
service调用N次,执行业务方法
destory只调用一次,卸载对象
ServletConfig
该接口是用来描述Servlet的基本信息的。
getServletName() 返回Servlet的名称,全类名(带着包名的类名)
getInitParameter(String key) 获取init参数的值(web.xml)
getInitParmeterNames() 返回所有的InitParameter 的 name 值,一般用作遍历初始化参数
getServletContext() 返回ServletContext对象,它是Servlet 的上下文,整个Servlet的管理者
ServletConfig 和 ServletContext的区别:
ServletConfig作用于某个Servlet实例,每个Servlet都有对应的ServletConfig,ServletContext作用于整个Web应用,一个Web应用对应一个ServletContext,多个Servlet实例对应一个ServletContext
Servlet的层次结构
Servlet--》 GenericServlet --》HttpServlet
HTTP请求有很多种类型,常用的有四种:
GET 读
POST 保存
PUT 修改
DELETE 删除
GenericServlet实现Servlet接口,同时为它的子类屏蔽了不常用的方法,子类只需要重写Servlet方法即可
HTTPServlet继承GenericServlet,根据请求类型进行分发处理,GET进入doGET方法,POST进入doPOST方法
开发者自定义的Servlet类只需要继承HTTPServlet即可,重新doGET和doPOST
package cn.soutwind.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("/demo03")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("GET请求");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("POST请求");
}
}
JSP
JSP本质上就是一个Servlet,JSP主要负责与用户交互,将最终的界面显示给用户,HTML+CSS+JS+Java 的混合文件
当服务器接收到一个后缀是jsp的请求时,将该请求交给JSP引擎处理,每一个JSP页面第一次被访问的时候,JSP引擎会将它翻译成一个Servlet文件,再由Web容器调用Servlet完成响应
单纯从开发的角度看,JSP就是在HTML中嵌入Java程序。
具体的嵌入方式有三种:
JSP脚本,执行Java逻辑代码
<% Java代码 %>
JSP声明:定义Java方法
<%! 声明 Java 方法 %>
JSP表达式:把Java对象直接输出到HTML页面中
<%= java变量 %>
<%!
public String test(){
return "Hello Word";
}
%>
<%
String str = test();
%>
<%=str%>
JSP内置对象9个
request:表示一次请求,HttpServletRequest。
response:表示一次响应,HttpServletResponse
pageContext:页面上下文,获取页面信息,PageContext
session:表示一次会话,保存用户信息,HttpSession
application:表示当前Web应用,全局对象,保存所有用户共享信息,ServletContext
config:当前JSP对应的Servlet的ServletConfig对象,获取当前Servlet信息
out:向浏览器输出数据,JSPWrite
page:当前JSP对应的Servlet对象,Servlet。
exception:表示JSP页面的发生的异常,Exception
常用的是request、response、session、application、pageContext
request常用方法:
String getParameter(String key)获取客户端传来的参数
void setAttribute(String key,Object value) 通过键值对的形式保存数据
Object getAttribute(String key) 通过key取出value
RequestDispatcher getRequestDispatcher(String path) 返回一个RequestDispatcher对象,该对象的forward方法用于请求转发
String[] getParameterValues() 获取客户端传来的多个同名参数
void setCharacterEncoding(String charset) 指定每个请求的编码
response常用方法:
sendRedirect(String path) 重定向,页面之间的跳转。
转发getRequestDispatcher 和 重定向sendRedirect的区别:
转发是将同一个请求传给下一个页面,重定向是创建一个新的请求传给下一个页面,之前的请求结束生命周期
转发:同一个请求在服务器之间传递,地址栏不变,也叫服务器跳转
重定向:由客户端发送一次新的请求来访问跳转后的目标资源,地址栏改变,也叫客户端跳转
如果两个页面之间需要通过request来传值,则必须使用转发,而不能使用重定向
例:用户登录,如果用户名和密码正确,则跳转到首页(转发),并且展示用户名,否则重新回到登录页面(重定向)
Session
用户会话
服务器无法识别每一次HTTP请求的出处(不知道来自于哪个终端)它只会接收到一个请求信号,所以就存在一个问题:将用户的响应发送给其他人,必须有一种技术来让服务器知道请求来自哪里,这就是会话技术
会话:就是客户端和服务器之间发生的一系列连续的请求和响应的过程,打开浏览器进行操作到关闭浏览器的过程
会话状态:指服务器和浏览器在会话过程中产生的状态信息,借助于会话状态,服务器能够把属于同一次会话的一系列请求和响应关联起来。
实现会话有两种方式:
session
cookie
属于同一次会话的请求都有一个相同的标识符,sessionID
session常用的方法:
String getId() 获取sessionID
void setMaxInactiveInterval 设置session的失效时间,单位为秒
int getMaxInactiveInterval 获取当前session的失效时间
void invalidate() 设置session立即失效
void setAttribute(String key,Object value) 通过键值对的形式来存储数据
Object getAttribute(String key) 通过键获取对应的数据
void removeAttribute(String key) 通过键删除对应的数据
Cookie
Cookie是服务端在HTTP响应中附带传给浏览器的一个小文本文件,一旦浏览器保存了某个Cookie,在之后的请求和响应过程中,会将此Cookie来回传递,这样就可以通过Cookie这个载体完成客户端和服务端之间的数据交互
创建Cookie
//创建Cookie
Cookie cookie = new Cookie("name","joker");
response.addCookie(cookie);
读取Cookie
// 读取Cookie
Cookie[] cookies = request.getCookies();
for (Cookie cookie: cookies){
out.write(cookie.getName() + ":" + cookie.getValue() + "</br>");
}
Cookie常用的方法
void setMaxAge(int age) 设置Cookie的有效时间,单位为秒
int getMaxAge() 获取Cookie的有效时间
Stirng getName() 获取Cookie的name
String getValue() 获取Cookie的value
Session和Cookie的区别
session: 保存在服务器
保存的数据是Object
会随着会话的结束而销毁
保存重要信息
cookie: 保存在浏览器
保存的数据是String
可以长期保存在浏览器,无会话无关
保存不重要的信息、
存储用户信息:
session: setAttribute("name","admin") 存
getAttribute("name") 取
生命周期:服务端:只要WEB应用重启就销毁,客户端:只要浏览器关闭就销毁
退出登录:session.invalidate()
cookie:response.addCookie(new Cookie("name","admin")) 存
Cookie[] cookies = request.getCookies();
for(Cookie cookie:cookies){
if (cookie.getName().equals("name")){
out.write("欢迎回来" + cookie.getValue());
}
}
取
生命周期:不随着服务端的重启而销毁,客户端:默认只要关闭浏览器就销毁,我们通过setMaxAge()方法设置有效期,一旦设置了有效期,则不随浏览器的关闭而销毁,而是由设置的时间来决定
退出登录:setMaxAge(0)
JSP内置对象作用域
page、request、session、application
setAttribute,getAttribute
page作用域:对应的内置对象是pageContext
request作用域:对应的内置对象是request
session作用域:对应的内置对象是session
application作用域:对应的内置对象是application
page
page只在当前页有效
request在一次请求内有效
session在一次会话内有效
application对应整个WEB应用
EL表达式
Expression Language 表达式语言,替代JSP页面中数据访问时的复杂编码,可以非常便携的取出域对象(pageContext、request、session、application)中保存的数据,前提是一定要先setAttribute,EL相当于在简化getAttribute
$(变量名) 变量名就是setAttribute对应的key值
EL对应四种域对象的默认查找顺序:
pageContext-》request-》session-》application
按照上述的顺序进行查找,找到立即返回,在application中无法找到,则返回null
指定作用域进行查找
pageContext:${pageScope.name}
request:${requestScope.name}
session:${sessionScope.name}
application:${applicationScope.name}
<%
User user = new User(1,"张三");
pageContext.setAttribute("user",user);
%>
<table>
<tr>
<th>编号</th>
<th>姓名</th>
</tr>
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
</tr>
JSTL
JSP Standard Tag Library JSP标准标签库,JSP为开发者体用的一系列的标签,使用这些标签可以完成一些逻辑处理,比如循环遍历集合,让代码更加简洁,不在出现JSP脚本穿插的情况。
实际开发中 EL 和 JSTL 结合起来使用,JSTL侧重于逻辑处理,EL负责展示数据。
JSTL的使用
需要导入jar包(两个jstl.jar standard.jar)存放的位置 web-WEB-INF
在JSP页面开始的地方导入JSTL标签库
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
在需要的地方使用
<c:forEach items="${requestScope.list}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
</tr>
</c:forEach>
JSTL优点:
提供了统一的标签
可以用于编写各种动态功能
核心标签库常用的标签:
set、out、remove、catch
set:向域对象添加数据
<c:set var="name" value="张三"></c:set>
${name}
<%
User user = new User(1,"张三");
request.setAttribute("user",user);
%>
${user.name}
<br>
<c:set target="${user}" property="name" value="李四"></c:set>
${user.name}
out:输出域对象中的数据
<c:set var="name" value="张三"></c:set>
<c:out value="${name}" default="没哟"></c:out>
remove:删除域对象中的数据
<c:remove var="name" scope="page"></c:remove>
<c:out value="${name}" default="没定义"></c:out>
catch:捕获异常
v
条件标签:if choose
<c:set var="num1" value="1"></c:set>
<c:set var="num2" value="2"></c:set>
<c:if test="${num1 > num2}">ok</c:if>
<c:if test="${num1 < num2}">fail</c:if>
<hr>
<c:choose>
<c:when test="${num1 > num2}">ok</c:when>
<c:otherwise>fail</c:otherwise>
</c:choose>
迭代标签:forEach
<c:forEach items="${list}" var="str" begin="2" end="5" step="2" varStatus="sta">
${sta} - ${str}<br>
</c:forEach>
格式化标签库常用的标签:
<%
request.setAttribute("data",new Date());
%>
<fmt:formatDate value="${data}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
<fmt:formatNumber value="1234.665" maxIntegerDigits="3" maxFractionDigits="1"></fmt:formatNumber>
过滤器(Filter)
功能:
用来拦截传入的请求和传出的响应
修改或以某种方式处理正在客户端和服务端之间交换的数据流
如何使用?
与使用Servlet类似,Filter是Java WEB提供的一个街口,开发者只需要定义一个类并且实现该接口即可。
package cn.soutwind.Filter;
import javax.servlet.*;
import java.io.IOException;
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
filterChain.doFilter(servletRequest,servletResponse);
}
}
web.xml 中配置Filter
<filter>
<filter-name>Character</filter-name>
<filter-class>cn.soutwind.Filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Character</filter-name>
<url-pattern>/login</url-pattern>
</filter-mapping>
注意:doFilter方法中处理完业务逻辑之后,必须添加filterChain.doFilter(servletRequest,servletResponse);否则请求/响应无法向后传递,一直停留在过滤器中
Filter的生命周期
当Tomcat启动时,通过反射机制调用Filter的无参构造函数创建实例化对象,同时调用init方法实现初始化,doFilter方法调用多次,当Tomcat服务关闭的时候,调用destory来销毁Filter对象。
无参构造函数:只调用一次,当Tomcat启动时调用(Filter一定要进行配置)
init方法:只调用一次,但Filter的实例化对象创建完成之后调用
doFilter:调用多次,访问Filter的业务逻辑都写在Filter中
destory:只调用一次,Tomcat关闭时调用
同时配置多个Filter,Filter的调用顺序是由web.xml中的配置顺序来决定的,写在上面的配置先调用,因为web.xml是从上往下顺序读取的
<filter>
<filter-name>Character</filter-name>
<filter-class>cn.soutwind.Filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Character</filter-name>
<url-pattern>/login</url-pattern>
</filter-mapping>
<filter>
<filter-name>my</filter-name>
<filter-class>cn.soutwind.Filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>my</filter-name>
<url-pattern>/login</url-pattern>
</filter-mapping>
也可以通过注解的方式来简化web.xml中的配置
@WebFilter("/login")
实际开发中Filter的使用场景
统一处理中文乱码
屏蔽敏感词
package cn.soutwind.Filter;
import javax.servlet.*;
import java.io.IOException;
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
String name = servletRequest.getParameter("name");
name = name.replaceAll("敏感词","***");
servletRequest.setAttribute("name",name);
filterChain.doFilter(servletRequest,servletResponse);
}
}
package cn.soutwind.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("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// req.setCharacterEncoding("UTF-8");
String name = (String) req.getAttribute("name");
System.out.println(name);
}
}
控制资源的访问权限
package cn.soutwind.Filter;
import com.sun.deploy.net.HttpResponse;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/download.jsp")
public class DownloadFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpSession session = request.getSession();
HttpServletResponse response = (HttpServletResponse) servletResponse;
String name = (String) session.getAttribute("name");
if (name != null){
filterChain.doFilter(servletRequest,servletResponse);
}else{
response.sendRedirect("index.jsp");
}
}
}
package cn.soutwind.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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String password= req.getParameter("password");
if(name.equals("admin") && password.equals("123456")){
HttpSession session = req.getSession();
session.setAttribute("name",name);
resp.sendRedirect("download.jsp");
}else{
resp.sendRedirect("index.jsp");
}
}
}
文件上传下载
JSP
input的type设置为file
form表单的method设置post,get请求会将文件名传给服务端,而不是文件本身
form表单的enctype设置multipart/form-data,以二进制的形式传输数据
Servlet
上传
package cn.soutwind.Servlet;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// InputStream inputStream = req.getInputStream();
// int temp = 0;
// while((temp = inputStream.read()) != -1){
// System.out.println(temp);
// }
try {
// 创建一个文件工厂
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
// 把请求的内容转为FileItem的集合
List<FileItem> list = servletFileUpload.parseRequest(req);
for (FileItem fileItem : list){
//有两种数据,一个是表单数据一个是文件数据
if(fileItem.isFormField()){
//表单数据
String name = fileItem.getName();
String value = fileItem.getString("UTF-8");
System.out.println(name + ":" + value);
}else{
//文件数据
String name = fileItem.getName();
String path = req.getServletContext().getRealPath("file/" + name);
InputStream inputStream = fileItem.getInputStream();
OutputStream outputStream = new FileOutputStream(path);
int temp = 0;
while((temp = inputStream.read()) != -1){
outputStream.write(temp);
System.out.println(temp);
}
inputStream.close();
outputStream.close();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
下载
package cn.soutwind.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.*;
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应方式
resp.setContentType("application/x-msdownload");
String filename= "1.jpg";
//设置下载后的文件名
resp.setHeader("Content-Disposition","attachment;filename=" + filename);
OutputStream outputStream = resp.getOutputStream();
String path = req.getServletContext().getRealPath("file/" + filename);
InputStream inputStream = new FileInputStream(path);
int temp = 0;
while((temp = inputStream.read()) != -1){
System.out.println(temp);
outputStream.write(temp);
}
inputStream.close();
outputStream.close();
}
}
Ajax
Asynchronous JavaScript And XML:异步的JavaScript和XML
Ajax不是新的编程,指的是一种交互方式,异步加载 ,客户端和服务端的数据交互更新在局部页面的技术,不需要刷新整个页面(拒不刷新)
优点:
局部刷新,效率更高
用户体验更好
<%--
Created by IntelliJ IDEA.
User: DELL
Date: 2023/8/24
Time: 19:36
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.5.1.min.js"></script>
<script type="text/javascript">
$(function (){
var btn = $("#btn");
btn.click(function (){
$.ajax({
url:'/test',
type:'post',
dataType:'text',
success:function (data){
var text = $("#txt");
text.before("<h1>" + data + "</h1>" + "<br>")
}
});
});
})
</script>
</head>
<body>
<input type="text" id="txt"><br>
<input type="button" id="btn" value="提交">
</body>
</html>
不能用表单提交请求,改用Jquery方式动态绑定事件来提交。
Servlet不能跳转到JSP,只能将数据返回
package cn.soutwind.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("/test")
public class TestServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String str = "Hello Word";
// req.setAttribute("str",str);
// req.getRequestDispatcher("test.jsp").forward(req,resp);
resp.getWriter().write(str);
}
}
传统的WEB数据交互 VS AJAX数据交互
客户端请求的方式不同:
传统,浏览器发送同步请求(form、a)
AJAX,异步引擎对象发送异步请求
服务器响应的方式不同:
传统,响应的一个完整的JSP页面(视图)
AJAX,响应需要的数据
客户端处理方式不同:
传统:需要等待服务器完成响应并且重新加载整个页面后,用户才能进行后续的操作
AJAX:动态更新页面中的局部内容,不影响用户的其他操作
基于JQuery的AJAX语法
$.ajax({属性})
常用的属性参数:
url:请求的后端服务地址
type:请求方式,默认get
data:请求参数
dataType:服务器返回的数据类型,text/json
success:请求传给的回调函数
error:请求失败的回调函数
complete:请求完成的回调函数(无论成功或者失败,都会调用)
JDBC
Java DataBase Connectivity是一个独立于特定数据库的管理系统,通用的SQL数据存取操作的公共接口。
定义了一组标准,为访问不同数据库提供了统一的途径。
JDBC体系结构
JDBC接口包括两个层面:
面向应用的API,供程序员使用
面向数据库的API,供厂商开发数据库的驱动程序
JDBC API
提供者:Java官方
内容:供开发者调用的接口
java.sql 和 javax.sql
DriverManager类
Connection接口
Statement接口
ResultSet接口
Drivermanager
提供者:Java 官方
作用:管理不同的JDBC驱动
JDBC驱动
提供者:数据库厂商
作用:负责连接不同的数据库
JDBC的使用
加载数据库驱动,Java程序和数据库之间的桥梁
获取Connection,Java程序与数据库的一次连接
创建Statement对象,由Connection产生,执行SQL语句
如果需要接受返回值,创建ResultSet对象,保存Statement执行之后所查询到的结果。
数据库连接池
JDBC开发流程
加载驱动(只需要加载一次)
建立数据库连接(Connection)
执行SQL语句(Statement)
ResultSet接收结果集(查询)
断开连接,释放资源
数据库连接对象是通过DriverManager来获取,每次获取都需要向数据库申请获取连接,验证用户名和密码,执行完SQL语句后断开连接,这样的方式会造成资源的浪费,数据连接资源没有得到很好的重复利用。
可以使用数据库连接池解决这一问题
数据库连接池的基本思想就是为数据库建立一个缓冲池,预先向缓冲池放入一定数量的连接对象,当需要获取数据库连接的时候,只需要从缓冲池取出一个对象,用完之后再放回缓冲池中,供下一次请求使用,做到了资源的重复利用,允许程序重复使用一个现有的数据库连接对象,而不需要重新创建。
当数据库连接池中没有空闲的连接时,新的请求就会进入等待队列,等待其他线程释放连接
数据库连接池的实现
JDBC的数据库连接池是哟韩Javax.sql.Datasourc接口来完成的,DataSource是Java官方提供的接口,使用的时候开发者并不需要自己来实现该接口,可以使用第三方的工具,C3P0是一个常用的第三方实现,实际开发中直接使用C3P0即可完成数据库连接池的操作
导入jar包
代码实现
package com.soutwind.Demo09;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0 {
public static void main(String[] args) {
try {
//创建连接池对象
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//加载驱动
dataSource.setDriverClass("com.mysql.jdbc.Driver");
//设置连接路径
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/express?characterEncoding=UTF-8");
//设置连接用户名
dataSource.setUser("root");
//设置密码
dataSource.setPassword("xxxxxx");
// 获取连接对象
Connection connection = dataSource.getConnection();
System.out.println(connection);
//归还连接对象
connection.close();
} catch (PropertyVetoException e) {
e.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
}
}
}
实际开发,将C3P0的配置信息定义在xml文件中,Java程序只需要加载配置文件即可完成数据库连接池的初始化操作。
配置文件的名字必须是c3p0-config.xml
初始化ComboPooledDataSource时,传入的参数必须是c3o0-config.xml中named-config标签的name属性值。
<?xml version="1.0" encoding="utf-8" ?>
<c3p0-config>
<named-config name="testc3p0">
<!-- 指定连接数据源的基本属性-->
<property name="user">root</property>
<property name="password">xxxxxx</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/express?characterEncoding=UTF-8</property>
<!-- 若数据库中连接数不足时,一次向数据库服务器申请多少个连接 -->
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池连接的对象 -->
<property name="initialPoolSize">2</property>
<!-- 数据库连接池中最小的数据库连接数 -->
<property name="minPoolSize">2</property>
<!-- 数据库连接池中最大的数据库连接数 -->
<property name="maxPoolSize">10</property>
</named-config>
</c3p0-config>
package com.soutwind.Demo09;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0_2 {
public static void main(String[] args) {
try {
//创建连接池对象
ComboPooledDataSource dataSource = new ComboPooledDataSource("testc3p0");
// 获取连接对象
Connection connection = dataSource.getConnection();
System.out.println(connection);
//归还连接对象
connection.close();
} catch (SQLException e){
e.printStackTrace();
}
}
}
xml文件得放在src目录下
DBUtils
DBUtils可以帮助开发者完成数据的封装(结果集到Java对象的映射)
导入jar包
ResultHandler接口是用来处理结果集,可以将查询到的结果集转为Java对象,提供了四种实现类
BeanHandler 将结果集映射成Java对象
BeanListHandler 将结果集映射成List集合
MapHandler 将结果集映射成Map对象
MapListHandler 将结果集映射MapList集合
package com.soutwind.Demo09;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import java.sql.Connection;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
ComboPooledDataSource dataSource = new ComboPooledDataSource("testc3p0");
Connection connection = null;
try {
connection = dataSource.getConnection();
QueryRunner queryRunner = new QueryRunner();
String sql = "select * from userinfo ";
System.out.println(queryRunner.query(connection,sql,new MapListHandler()));
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}