javaWeb+简单项目练习
Servlet
什么是Servlet?
Servlet是Java Web开发的基石,与平台无关的
服务器组件,它是运行Servlet容器/Web应用服务器/Tomcat,负责与客户端进行通信。
Servlet的功能:
1、创建并返回基于客户请求的动态HTML页面。
2、与数据库进行通信。
如何使用Servlet?
Servlet本身是一组接口,自定义一个类,并且实现Servlet接口,这个类就具备了接收客户端请求以及做出响应的功能。
package com.li.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>com.li.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/demo01</url-pattern>
</servlet-mapping>
- 基于注解的方式。
@WebServlet("/demo01")
public class MyServlet extends HttpServlet {
}
上述两种配置方式结果完全一致,将demo01与MyServlet进行映射,即在浏览器地址栏中直接访问demo01就可以映射到MyServlet
Servlet的生命周期
1、当浏览器访问Servlet的时候,Tomcat会查询当前Servlet的实例化对象是否存在,如果不存在,则通过反射机制动态创建对象,如果存在,直接执行第三步。
2、调用init方法完成初始化操作
3、调用service方法完成业务逻辑操作
4、关闭tomcat时,会调用destory方法,释放当前对象所占用的资源。
Servlet的生命周期方法:无参构造函数,init,service,destory
1、无参构造函数只调用一次,创建对象
2、init只调用一次,初始化对象
3、service调用N次,执行业务方法
4、destory只调用一次,
ServletConfig
该接口是用来描述Servlet的基本信息的。
getServletName() 返回Servlet的名称,全类名(带着包名的类名)
getInitParameter(String key) 获取init参数的值(web.xml)
getInitParameterNames() 返回所有的initparamter的name值,一般用作遍历初始化参数
getServletContext() 返回ServletContext对象,它是Servlet的上下文,整个Servlet的管理者。
ServletConfig和ServletContext的区别:
ServletConfig作用于某个Servlet实例,每个Servlet都有对应的ServletConfig,ServletContext作用于整个Web应用,一个Web应用对应一个ServletContext,多个Servlet实例对应一个ServletContext。
一个是局部对象,一个是全部对象。
Servlet的层次结构
Servlet---》GenericServlet---》HttpServlet
HTTP请求有很多类型,常用的有4种:
GET 读取
POST 保存
PUT 修改
DELETE 删除
CRUD(create read update delete)
GenericServlet实现Servlet接口,同时为它的子类屏蔽了不常用的方法,子类只需要重写Servlet方法即可。HttpServlet继承GenericServlet,根据请求类型进行分发处理,GET进入doGET方法,POST进入doPOST方法。
开发者自定义的Servlet类只需要继承HttpServlet即可,重写doGet和doPost。
package com.li.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 doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("GET");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("POST");
}
}
JSP
JSP本质上就是Servlet,JSP主要负责与用户交互,将最终的界面呈现给用户,HTML+CSS+JS+Java的混合文件。
当服务器接收到一个后缀是jsp的请求时,将该请求交给jsp引擎去处理,每一个jsp页面第一次被访问的时候,JSP引擎会将它翻译成一个Servlet文件,再由web容器调用Servlet来完成响应。
单纯从开发的角度看,JSP就是在HTML中嵌入Java程序。
具体的嵌入方式有3种:
1、JSP脚本:执行Java逻辑代码
<% Java代码 %>
2、JSP声明:定义Java方法
<%!
声明Java方法
%>
3、JSP表达式:把Java对象直接输出到HTML页面中
<%= Java变量
%>
例子:
<%!
public String test(){
return "Hello world";
}
%>
<%
String str=test();
%>
<%=str%>
JSP内置对象 9个
request:表示一次请求,HttpServletRequest。
response:表示一次响应,HttpServletResponse。
pageContext:页面上下文,获取页面信息,PageContext。
Session:表示一次会话,保存用户信息,HttpSession。
application:表示当前的Web应用,全局对象,保存所有用户共享信息,ServletContext。
config:当前JSP对应的Servlet的ServletConfig对象, 获取当前Servlet的信息
out:向浏览器输出数据,JspWriter。
page:当前JSP对应的Servlet对象,
exception:表示JSP页面发生的异常,Exception。
常用的是request、response、session、application、pagecontext
request常用的方法:
1、String getParameter(String key)获取客户端传来的数据
2、void setAttribute(String key,object value)通过键值对的形式保存数据。
3、Object getAttribute(String key)通过key取出value。
4、RequestDispatcher getRequestDispatcher(String path)返回一个RequestDispatch对象,,方法用于请求转发。
5、String[] getParameterValues()获取客户端传来的多个同名参数。
6、void setCharacterEncoding(String charset)指定每个请求的编码。
常见的异常|http常见的状态码
200:正常
404:资源找不到
400:请求类型不匹配
500:Java 程序抛出异常 代码有问题
response常用方法:
1、sendRedirect(String path)重定向,页面之间的跳转
转发getRequestDispatcher和重定向sendRedirect的区别:
转发是将同一个请求传给下一个页面,重定向是创建一个新的请求传给下一个页面,之前的请求结束生命周期。
转发:同一个请求在服务器之间传递,地址栏不变,也叫服务器跳转
重定向:由客户端发送一次新的请求来访问跳转后的目标资源,地址栏改变,也叫客户端跳转。
如果两个页面之间需要通过request来传值,则必须使用转发,不能使用重定向。
用户登录,如果用户名和密码正确,则跳转到首页(转发),并且展示用户名,否则重新回到登录页面(重定向)
例子:login
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/check.jsp" method="post">
用户名:<input type="text" name="username"/> <br/>
密码: <input type="password" name="password"/><br/>
<input type="submit" value="登录">
</form>
</body>
</html>
check
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username.equals("admin") && password.equals("123456")) {
//登录成功
request.setAttribute("name", username);
request.getRequestDispatcher("welcome.jsp").forward(request, response);
} else {
//登录失败
response.sendRedirect("login.jsp");
}
%>
</body>
</html>
welcome
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
String name = (String) request.getAttribute("name");
%>
欢迎回来!<%=name%>
</body>
</html>
Session
用户会话
服务器无法识别每一次HTTP请求的出处(不知道来自于哪个终端),它只会接受到一个请求信号,所以就存在一个问题:将用户的响应发送给其他人,必须有一种技术来让服务器知道请求来自哪,这就是会话技术。
会话:就是客户端和服务器之间发生的一系列连续的请求和响应的过程,打开浏览器进行操作到关闭浏览器的过程。
会话状态:指服务器和浏览器在会话过程中产生的状态信息,借助于会话状态,服务器能够把属于同一次会话的一系列请求和响应关联起来。
实现会话有两种方法:
-
Session(内置对象)
-
Cookie(不是内置对象)
属于同一次会话的请求都有一个相同的标识符,sessionID
session常用的方法:
String getid() 获取sessionID
void setMaxINactivelnterval(int interval) 设置session的失效时间,单位为秒。
int getMaxInactiveInterval() 获取当前session的失效时间
void invalidate 设置session立即失效
void setAttribute(String key,Object value) 通过键值对的形式来存储数据
Object getAttribute(String key) 通过键获取对应的数据
void removeAttribute(String key) 通过键删除对应的数据
Cookic
Cookic是服务端在HTTP响应中附带传给浏览器的一个小文本文件,一旦浏览器保存了某个Cookic,在之后的请求和响应过程中,会将次Cookic来回传递,这样就可以通过Cookic这个载体完成客户端和服务端的数据交互。
Cookic
- 创建cookie
Cookie cookie = new Cookie("name","张三");
response.addCookie(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的有效时间
String 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内置对象的作用域
4个JSP四大作用域
page、request、session、application
共同点(都能存取数据),方法:setAttribute、getAttribute
page作用域:对应的内置对象是pageContext。
request作用域:对应的内置对象是request。
session作用域:对应的内置对象是session。
application作用域:对应的内置对象是application。
大小关系:page<request<session<application。
page只在当前页面有效。
request在一次请求内有效。
session在一次会话内有效。
application对应整个web应用的。
- 网站的访问量统计
<%
Integer count = (Integer) application.getAttribute("count");
if (count == null) {
count = 1;
application.setAttribute("count", count);
} else {
count++;
application.setAttribute("count", count);
}
%>
您是当前的第<%=count%>位访客。
EL表达式
Expression Language表达式语言,替代JSP页面中数据访问时的复杂编码,可以非常便捷地取出域对象(pageContext、request、session、application)中保存的数据,前提是一定要先setAttribute,EL就相当于简化getAtribute
语法:${变量名} 变量名就是setAtribute对应的key值。
EL.JSP
<%
request.setAttribute("name","LJY");
request.getRequestDispatcher("el2.jsp").forward(request,response);
%>
el2.jsp
<%
String name = (String)request.getAttribute("name");
%>
<%=name%>
<hr/>
${name}
EL对于4种域对象的默认查找顺序:
pageContext->request->session->application
按照上述的顺序进行查找,找到立即返回,在application中也无法找到,则返回null
指定作用域进行查找
pageContext:${pageContextScope.name}
request:${requestScope.name}
session:${sesseionScope.name}
application:${applicationScope.name}
数据级联:
EL执行表达式:
&& || ! <> <= <= ==
如:${num1&&num2}
&& and
|| or
! not
== rq
!= ne
< lt
> gt
<=le
>=ge
empty(判断是否为空) 如: 变量为null、长度为0的String、size为0的集合 语法:
${empty xxx}
JSTL
JSP Standard Tag Library JSP 标准标签库,JSP为开发者提供的一系列的标签,使用这些标签可以完成一些逻辑处理,比如循环遍历集合,让代码更加及简洁,不再出现JSP脚本穿插的情况。
实际开发中EL和JSTL结合起来使用,JSTL侧重于逻辑处理,EL负责展示数据。
JSTL的使用
1、需要导入jar包(两个 jstl.jar standard.jar)
2、在JSP页面开始的地方导入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3、在需要的地方使用
<c:forEach items="${list}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.score}</td>
<td>${user.address.value}</td>
</tr>
</c:forEach>
JSTL优点:
1、提供统一的标签
2、可以用于编写各种动态功能
常用标签:
- set、out、remove、catch
set:向域对象中添加数据
相当于如下语法:
<%
request.setAttribute(key,value)
%>
本身:
<c:set var="name" value="tom" scope="request"></c:set>
${requestScope.name}
out:输出域对象中的数据
<c:set var="name" value="tom"> </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:捕获异常
<c:catch var="error">
<%
int a=10/0;
%>
</c:catch>
${error}
条件标签 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>
迭代标签
<c:forEach items="${list}" var = "str" begin="2" end="3" step="2" varStatus="sta">
${sta.count}、${str} <br/>
</c:forEach>
格式化标签库常用的标签:
时间格式化:
<%
request.setAttribute("date", new Date());
%>
<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
函数标签库常用的标签:
<%
request.setAttribute("info", "java,c");
%>
${fn:contains(info,"Python" )}<br/>
${fn:startsWith(info, "java")}<br/>
${fn:endsWith(info,"c")}<br/>
${fn:indexOf(info, "va")}<br/>
${fn:replace(info, "c","Python" )}<br/>
${fn:substring(info,2 ,3 )}<br/>
过滤器
Filter
功能:
1、用来拦截传入的请求和传出的响应 。
2、修改或以某种方式处理正在客户端和服务端之间交换的数据流。
如何使用?
与使用Servlet类似,Filter是Java Web提供的一个接口,开发者只需要自定义一个类并且实现该接口即可。
package com.li.Filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterFilter 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>CharacterFilter</filter-name>
<filter-class>com.li.Filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterFilter</filter-name>
<url-pattern>/login</url-pattern>
<url-pattern>/test</url-pattern>
</filter-mapping>
注意:dofilter方法中处理完业务逻辑之后,必须添加filterChain.doFilter(servletRequest, servletResponse); 这一行代码。
否则请求/响应无法向后传递,一直停留在过滤器中。
Filter的生命周期
当Tomcat启动时,通过反射机制调用Filter的无参构造函数创建实例化对象,同时调用init方法实现初始化,foFilter方法调用多次,当Tomcat服务关闭的时候,调用destory来销毁Filter对象。
无参构造函数:只调用一次,当Tomcat启动时调用(Filter一定要进行配置)
init方法:只调用一次,当Filter的实例化对象创建完成之后调用。
doFilter:调用多次,访问Filter的业务逻辑都写在Filter中。
destory:只调用一次,Tomcat关闭时调用。
同时配置多个Filter,Filter的调用顺序是由web.xml中的配置顺序来决定的,写在上面的配置先调用,因为web.xml是从上到下的顺序读取的。
也可以通过注解的方式来简化web.xml中的配置
实际开发中Filter的使用场景:
1、统一处理中文乱码。
2、屏蔽敏感词。
package com.li.Filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/test")
public class WordFilter 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 com.li.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 {
req.setCharacterEncoding("UTF-8");
String name = (String) req.getAttribute("name");
System.out.println(name);
}
}
3、控制资源的访问权限。
文件上传下载(经常使用)
- JSP
1、input的type设置为file
2、form表单的method设置为post,get请求会将文件名传给服务端,而不是文件本身。
3、form表单的enctype设置为multipart/form-data,以二进制的形式传输数据
<form enctype="multipart/form-data" action="/uplopad" method="post">
<input type="file" name="img"><br/>
<input type="submit" value="提交">
</form>
- Servlet
package com.li.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
@WebServlet("/uplopad")
public class UploadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过输入流获取客户端传来的数据流
InputStream inputStream = req.getInputStream();
Reader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
//通过输出流将数据输出到本地硬盘
//获取文件夹的绝对路径
String path = req.getServletContext().getRealPath("file/copy.txt");
FileOutputStream outputStream1 = new FileOutputStream(path);
Writer writer = new OutputStreamWriter(outputStream1);
BufferedWriter bufferedWriter = new BufferedWriter(writer);
// OutputStream outputStream = new FileOutputStream("file");
String str = "";
while ((str = bufferedReader.readLine()) != null) {
bufferedWriter.write(str);
}
bufferedWriter.close();
writer.close();
outputStream1.close();
bufferedReader.close();
reader.close();
inputStream.close();
}
}
使用组件写:fileupload组件
Fileupload组件可以将所有的请求信息都解析成Filelteam对象,可以通过对Filelteam对象的操作完成上传,面向对象的思想。
try {
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
List<FileItem> list = servletFileUpload.parseRequest(req);
for (FileItem fileItem:list){
if(fileItem.isFormField()){ //是个文本 输入框
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8");
System.out.println(name+":");
}else{ //是文件
String fieldName = fileItem.getFieldName();
long size = fileItem.getSize();
System.out.println(fieldName+":"+size+"Byte");
InputStream inputStream = fileItem.getInputStream();
String path = req.getServletContext().getRealPath("file/"+fieldName);
OutputStream outputStream = new FileOutputStream(path);
int temp = 0;
while((temp = inputStream.read())!=-1){
outputStream.write(temp);
}
outputStream.close();
inputStream.close();
System.out.println("上传成功");
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
文件下载
jsp
<body>
<a href="/download">1.png</a>
</body>
package com.li.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String type = req.getParameter("type");
String fileName = "";
//设置响应的方式
resp.setContentType("application/x-msdownload");
//设置下载之后文件名
resp.setHeader("Content-Disposition", "attachment;filename=" + fileName);
//获取输出流
ServletOutputStream outputStream = resp.getOutputStream();
String path = req.getServletContext().getRealPath("file/xx.jpg");
InputStream inputStream = new FileInputStream(path);
int temp = 0;
while ((temp = inputStream.read()) != -1) {
outputStream.write(temp);
}
inputStream.close();
outputStream.close();
}
}
Ajax
什么是Ajax
Asynchronous JavaScript And XML:异步的JavaScript和XML
AJAX不是新的编程语言,指的是一种交互方式,异步加载,指的是客户端和服务器的数据交互是更新在局部页面的技术,不需要刷新整个页面(局部刷新)
优点
1、局部刷新,效率更高
2、用户体验更好
3、各个操作之间互不影响
基于jQuery的Ajax
不能用表单提交请求,改用jQuery方式动态绑定事件来提交。
servlet不能跳转到jsp,只能将数据返回
package com.li.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 {
String id = req.getParameter("id");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String str = "hello word";
resp.getWriter().write(str);
// req.setAttribute("str",str);
// req.getRequestDispatcher("test.jsp").forward(req,resp);
}
}
传统的WEB数据交互VS Ajax数据交互的区别
客户端请求方式不同:
传统:浏览器发送同步请求(form、a)
Ajax:异步引擎对象发送异步请求。
服务器响应的方式不同:
传统:响应一个完整JSP页面(视图)
Ajax:响应需要的数据
客户端处理方式不同:
传统:需要等待服务器完成响应并且重新加载整个页面之后,用户才能进行后续的操作
Ajax:动态更新页面中的局部内容,不影响用户的其他操作。
Ajax原理
基于jQuery的Ajax语法
$.ajax({属性})
常用的属性参数:
url:请求的后端服务地址
type:请求方式,默认是get
data:请求参数
dateType:服务器返回的数据类型,text/json(表示:对象)
success:请求成功的回调函数
error:请求失败的回调函数
complete:请求完成的回调函数(无论成功或者失败,都会调用)
JSON
JavaScript Object Notation,一种轻量级数据交互格式,完成js与java等后端开发语言对象数据之间的转换
客户端和服务器之间传递对象数据,需要用JSON格式。
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的使用
1、加载数据库驱动,Java程序和数据库之间的桥梁
2、获取Connection,Java程序与数据库的一次连接
3、创建Statement对象,由Connection产生,执行SQL语句
4、如果需要接受返回值,创建ResultSet对象,保存Statement执行之后所查询到的结果。
增删改用executeUpdate
查询用executeQuery
package com.li.jdbc;
import java.sql.*;
public class Test {
public static void main(String[] args) {
try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:3306/smbms?userUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "ljy123456";
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
// String sql = "insert into xxx(xx,xx) values('xx','xx')";
// String sql = "update student set name = 'lisi'";
// String sql = "delete from student";
// Statement statement = connection.createStatement();
// int result =statement.executeUpdate(sql);
String sql = "select * from student";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
Integer id = resultSet.getInt("id");
String name = resultSet.getString(2);
Double score = resultSet.getDouble(3);
System.out.println(id + "-" + name + "-" + score);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
}
}
}
PreparedStatement
Statement的子类,提供了SQL占位符的功能
使用Statement进行有两个问题:
1、需要频繁拼接String字符串,出错率高。
2、存在SQL注入的风险。
SQL注入:利用某些系统没对用户输入的信息进行充分检测,在用户输入的数据中注入非法的SQL语句,从而利用系统的SQL引擎完成恶意行为的做法。
package com.li.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PreparedStatement {
public static void main(String[] args) {
try {
//加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接
String url = "jdbc:mysql://localhost:3306/smbms?userUnicode=true&characterEncoding=utf-8";
String user = "root";
String password = "ljy123456";
Connection connection = DriverManager.getConnection(url, user, password);
String username = "lisi";
String mypassword = "000";
String sql = "select *from t_user where username=? and passwor=?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, username);
preparedStatement.setString(2, mypassword);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
}
}
}
数据库连接池
JDBC开发流程
- 加载驱动(只需要加载一次)
- 建立数据库连接(Connection)
- 执行SQL语句(Statement)
- ResultSet接收结果集(查询)
- 断开连接,释放资源
数据库连接对象是通过DriverManager来获取的,每次获取都需要向数据库申请获取连接,验证用户名和密码,执行完SQL语句后断开连接,这样的方式会造成资源的浪费,数据库连接资源没有得到很好的重复利用。
可以使用数据库连接池来解决这个问题。
数据库连接池的基本思想就是为数据库建立一个缓存池,预先向缓冲池中放入一定数量的连接对象,对需要获取数据库连接的时候,只需要从缓冲池中取出一个对象,用完之后再放回到缓冲池中,供下一次请求使用,做到了资源的重复利用,允许程序重复使用一个现有的数据库连接对象,而不需要重新创建。
当数据库连接池中没有空闲的连接时,新的请求就会进入等待队列,等待其他线程释放连接。
数据库连接池实现
JDBC的数据库连接池使用Javax.sql.DataSource接口来完成的,DataSource是Java官方提供的接口,使用的时候开发者并不需要自己来实现该接口,可以使用第三方的工具,C3P0是一个常用的第三方实现,实际开发中直接使用C3P0即可完成数据库连接池的操作。
C3P0拿到的connection
com.mchange.v2.c3p0.impl.NewProxyConnection@55ca8de8 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@2c34f934]
传统方式拿到的connection
com.mysql.cj.jdbc.ConnectionImpl@5ffead27
代码实现
package com.li.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "ljy123456";
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
//还回到数据库连接池中
connection.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
}
}
}
实际开发,将C3P0的配置信息定义在xml文件中,Java 程序只需要加载配置文件即可完成数据库连接池的初始化操作。
1、配置文件的名字必须是c3p0-config.xml
2、初始化ComboPooledDataSource时,传入的参数必须是C3P0-confing.xml中named-config标签的name属性值。
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
<named-config name="test03">
<!-- 指定连接书就可以的基本属性-->
<property name="user">root</property>
<property name="password">ljy123456</property>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=UTF-8
</property>
<!-- 若数据库中连接数不足时,一次向数据库服务器申请多少个连接-->
<property name="acquireIncrement">5</property>
<!--初始化数据库连接池时连接的数量-->
<property name="initialPoolSize">20</property>
<!--数据库连接池中最小的数据库连接数-->
<property name="minPoolSize">2</property>
<!--数据库连接池中最大的数据库连接数-->
<property name="maxPoolSize">40</property>
</named-config>
</c3p0-config>
读取代码
package com.li.test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.w3c.dom.CDATASection;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
public class DataSourceTest {
public static void main(String[] args) {
try {
//创建c3p0
ComboPooledDataSource dataSource = new ComboPooledDataSource("test03");
Connection connection = dataSource.getConnection();
System.out.println(connection);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
DBUtils
DBUtils可以帮助开发者完成数据的封装(结果集到Java对象的映射)
1、导入jar包 (dbutils)
ResultHandler接口是用来处理结果集,可以将查询到的结果集转换成Java对象,提供了4种实现类。
- BeanHandler 将结果集映射成Java对象 Student
- BeanListHandler 将结果集映射成List集合List
- MapHandle 将结果集映射成Map对象
- MapListHandle 将结果集映射成MapListHandle结合
public static Student findByDBUtils() {
Student student = null;
Connection connection = null;
try {
connection = dataSource.getConnection();
String sql = "select * from student where id = 30";
QueryRunner queryRunner = new QueryRunner();
student = queryRunner.query(connection, sql, new BeanHandler<Student>(Student.class));
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return student;
}
对比代码+全代码:
package com.li.test;
import com.li.entity.Student;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import javax.management.Query;
import java.sql.*;
public class DBUtils {
private static ComboPooledDataSource dataSource;
static {
dataSource = new ComboPooledDataSource("test03");
}
public static void main(String[] args) {
Student student = findById();
System.out.println(student);
Student student1 = findByDBUtils();
System.out.println(student1);
}
public static Student findByDBUtils() {
Student student = null;
Connection connection = null;
try {
connection = dataSource.getConnection();
String sql = "select * from student where id = 30";
QueryRunner queryRunner = new QueryRunner();
student = queryRunner.query(connection, sql, new BeanHandler<Student>(Student.class));
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return student;
}
public static Student findById() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
Student student = null;
try {
connection = dataSource.getConnection();
String sql = "select * from student where id = 30";
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Integer id = resultSet.getInt(1);
String name = resultSet.getString(2);
Double score = resultSet.getDouble(3);
Date birthday = resultSet.getDate(4);
student = new Student(id, name, score, birthday);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
preparedStatement.close();
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return student;
}
}
package com.li.entity;
import java.util.Date;
public class Student {
private Integer id;
private String name;
private Double score;
private Date birthday;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Student(Integer id, String name, Double score, Date birthday) {
this.id = id;
this.name = name;
this.score = score;
this.birthday = birthday;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", score=" + score +
", birthday=" + birthday +
'}';
}
}
MVC
是一种开发模式,将程序分层的一种思想。
M:Model 业务数据(Service、repository、entity)
V:view 视图(JSP、HTML、APP客户端)
C:Controller 控制(Servlet、Handler、Action)
请求进入Java Web应用后,Controller接收该请求,进行业务逻辑处理,最终将处理的结果再返回给用户(View+Model)
Controller--》service---》Repository --》DB
请求进入Controller,进行业务处理,从Controller中将Model带到View中响应给用户。
项目资源链接: