JavaWeb-2
学习视频:B站 狂神说Java – https://www.bilibili.com/video/BV12J411M7Sj
学习资料笔记:CSDN – https://blog.csdn.net/DDDDeng_/article/details/106826674
JavaWeb:网页编程 B/S
- B/S即浏览器/服务器(browser/server),不需要安装客户端,采用浏览器浏览就可以了,指的是软件系统的结构.
网络编程:TCP/IP C/S
- C/S 指的就是 客户端/服务器 Client/server。
web开发:
- web,网页的意思。例如 www.baidu.com
- 静态web
- html, css
- 提供给所有人看的, 这个数据始终不会发生变化
- 动态Web
- 几乎是所有的网站。比如淘宝
- 提供给所有人看到数据始终会发生变化。 每个人在不同的事件,不同的地点看到的信息各不相同。从服务端获取数据,Web界面因人而变
- 技术栈:Servlet / JSP, ASP, PHP
在Java中,动态web资源开发的技术统称为 JavaWeb。
1、Cookie、Session
Cookie: 曲奇饼干
session:会话
1.1、会话
会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器这个过程可以称之为会话。
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过
那么对于一个网站而言,如何证明你来过呢 ?下面是两种方式:
客户端、服务端:
- 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了;cookie
- 服务器登记你来过了,下次你来的时候我来匹配你;session
意思就相当于:
- 服务端给客户端开了一个证明,下次你拿着证明来,就可以报道,即cookie
- 服务端自己进行登记了,下次你来,服务端自己在登记表里面找你的信息,找到了就让你进去。session。
1.2、保存会话的两种技术
cookie
- 客户端技术(通过响应,请求)
session
- 服务器技术,利用这个技术,可以保存用户的会话信息。我们可以把信息或者数据放在Session中!
常见问题:
网站登录之后,下次不用再登录了,第二次就直接上去了。 这就是客户端和服务端成功的进行了匹配, 把曾经两个人之间的交易记录(存放在 cookie / session)拿出来能够成功比对。
查看一下Cookie类:都是一些 get 和 set 的方法,用来存放和获取数据的。
1.3、Cookie 客户端技术
Cookie: 服务端给访问的客户端开了一个证明/信件, 下一次 客户端拿着信件/证明来, 就能直接进去服务端。
客户端技术的例子:
cookie:
-
创建一个Servlet程序,CookieDemo01:服务器先请求客户端,得到其cookie信息。然后服务器响应客户端,生成一个cookie。
- 在这里,我们试图去保存一个 cookie信息是用户上次访问的时间信息。
- 注意:这个Cookie 是 客户端的,在客户端的手里,客户端拿着证明去 将访问进入服务端。 所以,应该是 服务端从客户端 获取 cookie。
- 我们可以去设置cookie的存活时间 有效时间。
package com.AL.servlet; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.Date; // 保存用户上一次访问的时间 public class CookieDemo01 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //服务器告诉你, 你来的时间.把这个时间封装成一个发票,你下次带着发票来,我就知道是你来了 // 解决中文乱码 req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html; charset=utf-8"); PrintWriter out = resp.getWriter(); // Cookie,服务器从客户端获取,查看你的发票. 查看你啥时来的,是不是这个班的人 Cookie[] cookies = req.getCookies(); //返回的是数组,表明cookie可能存在多个 // 判断cookie是否存在 if (cookies!=null){ // 当存在时的输出 out.write("你上次访问的时间为:"); for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; //获取cookie的名字 if (cookie.getName().equals("lastLoginTime")){ // 获取cookie的值 long lastLoginTime = Long.parseLong(cookie.getValue()); Date date = new Date(lastLoginTime); out.write(date.toLocaleString()); } } }else { out.write("This is you first time"); } // 服务器给客户端响应一个cookie Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + ""); // cookie有效期设置为1天. 以秒为单位 cookie.setMaxAge(24*60*60); resp.setCharacterEncoding("utf-8"); resp.addCookie(cookie); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
-
web.xml配置文件。进行注册Servlet 和 Servlet的路径映射。
<?xml version="1.0" encoding="UTF-8"?> <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_4_0.xsd" version="4.0"> <servlet> <servlet-name>CookieDemo01</servlet-name> <servlet-class>com.AL.servlet.CookieDemo01</servlet-class> </servlet> <servlet-mapping> <servlet-name>CookieDemo01</servlet-name> <url-pattern>/c1</url-pattern> </servlet-mapping> </web-app>
-
启动Tomcat,进行测试。输入 localhost:8080/c1,结果为:
删除cookie:
1.创建一个cookie,且名字必须和要删除的名字一样:
package com.AL.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CookieDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 创建一个cookie. 名字必须要和删除的目标cookie一样
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
// 将cookie有效期设置为0, 立马失效
cookie.setMaxAge(0);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
2.配置文件web.xml:
<servlet>
<servlet-name>CookieDemo02</servlet-name>
<servlet-class>com.AL.servlet.CookieDemo02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CookieDemo02</servlet-name>
<url-pattern>/c2</url-pattern>
</servlet-mapping>
3.启动Tomcat,进行测试。 localhost:8080/c2, 结果显示 cookie立马失效。
小结:
cookie:
- 服务器先向客户端请求,去获取cookie信息。请求中拿到cookie信息。想要得到你的发票,如果你有发票,则将发票展示出来;没有,则给你一个新的发票。
- 服务器请求完之后,开始响应给客户端cookie。将得到的信息去生成一个cookie,进行展示,表明你是新来的还是 已经来过。
在这个实现cookie中使用的函数有:
Cookie[] cookies=req.getCookiles();//获得cookie
cookie.getName();//获得cookie中的key
cookie.getValue();//获得cookie中的value
new Cookie("lastLoginTime",System.currentTimeMillis()+"");//新建一个cookie
cookie.setMaxAge(24*60*60);//设置cookie的有效期
resp.addCookie(cookie);//响应给客户端一个cookie
cookie:一般会保存在本地的 用户目录下 appdata
一个网站cookie是否存在上限?
- 一个cookie只能保存一个信息
- 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie
- cookie大小有限制4kb
- 300个cookie浏览器上限
删除cookie:
- 不设置有效期,关闭浏览器,自动失效;
- 设置有效期时间为0;
一关闭浏览器,cookie就自动失效了。
中文数据传递
-
创建一个cookie:
package com.AL.servlet; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.Date; public class CookieDemo03 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html; charset=utf-8"); //服务器告诉你, 你来的时间.把这个时间封装成一个发票,你下次带着发票来,我就知道是你来了 // Cookie,服务器从客户端获取,查看你的发票. 查看你啥时来的,是不是这个班的人 Cookie[] cookies = req.getCookies(); //返回的是数组,表明cookie可能存在多个 PrintWriter out = resp.getWriter(); // 判断cookie是否存在 if (cookies!=null){ // 当存在时的输出 out.write("你上一次访问的时间是:"); //out.write("you last time is:"); for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; //获取cookie的名字 if (cookie.getName().equals("name")){ // 获取cookie的值 //out.write(cookie.getValue()); out.write(URLDecoder.decode(cookie.getValue(),"UTF-8")); // 解码 } } }else { out.write("这是你第一次访问本站"); } // 服务器给客户端响应一个cookie. 编码: URLEncoder.encode() Cookie cookie = new Cookie("name", URLEncoder.encode("坤坤","utf-8")); // cookie有效期设置为1天. 以秒为单位 cookie.setMaxAge(24*60*60); resp.addCookie(cookie); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
-
web.xml配置文件。发布Servlet程序。
<servlet> <servlet-name>CookieDemo03</servlet-name> <servlet-class>com.AL.servlet.CookieDemo03</servlet-class> </servlet> <servlet-mapping> <servlet-name>CookieDemo03</servlet-name> <url-pattern>/c3</url-pattern> </servlet-mapping>
-
处理请求参数传递编码问题: 使用编码和解码的方式,使中文不产生乱码。
- java中编码:URLEncoder.encode(strUri, “UTF-8”);
- java中解码:URLDecoder.decode(strUri, “UTF-8”);
1.4、Session(重点)
什么是Session:
- 服务器会给每一个用户(浏览器)创建一个Session对象
- 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在
- 用户登陆之后,整个网站它都可以访问!–>保存用户的信息;保存购物车的信息
Session和cookie的区别:
- Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
- Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)
- session由服务器创建,且保存在服务器中。
Session使用场景:
-
保存一个登陆用户的信息;
-
购物车信息;
-
在整个网站中经常会使用的数据,我们将它保存在session中
创建一个Session程序
- 创建一个session程序。session对象中去存储一个字符串 name
- 每个客户端的sessionID是唯一的
package com.AL.servlet;
import com.AL.pojo.Person;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
// session。 存放一个字符串
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8"); // 使文档可以访问,还有编码
//得到一个session
HttpSession session = req.getSession();
// 给session中存放东西。 服务器对客户进行登记
//session.setAttribute("name", new Person("鑫仔",1));
session.setAttribute("name", "鑫仔");
// 获取session的ID。 且每个客户端的sessionID是唯一的
String sessionId = session.getId();
//判断Session是否是新建的
if (session.isNew()){
resp.getWriter().write("Session创建成功,ID为"+sessionId);
}else {
resp.getWriter().write("session已经在服务器中创建了,ID为"+sessionId);
}
//Session创建的时候做了什么事情
// Cookie cookie = new Cookie("JSESSIONID", sessionId);
// resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
- 配置 web.xml文件。 注册servlet和servlet的映射路径。
<servlet>
<servlet-name>SessionDemo01</servlet-name>
<servlet-class>com.AL.servlet.SessionDemo01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionDemo01</servlet-name>
<url-pattern>/s1</url-pattern>
</servlet-mapping>
- 启动Tomcat,进行测试。localhost:8080/s1, 结果为:
获取Session的程序
1.创建一个获取Session的session程序:
package com.AL.servlet;
import com.AL.pojo.Person;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8"); // 使文档可以访问,还有编码
//得到一个session
HttpSession session = req.getSession();
// Person person = (Person) session.getAttribute("name");
// System.out.println(person.toString());
String name = (String) session.getAttribute("name");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
2.配置 web.xml文件。 这个相当于web容器,发布 Servlet程序。
<servlet>
<servlet-name>SessionDemo02</servlet-name>
<servlet-class>com.AL.servlet.SessionDemo02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SessionDemo02</servlet-name>
<url-pattern>/s2</url-pattern>
</servlet-mapping>
3.启动Tomcat,进行测试: localhost:8080/s2。在java控制台可以得到输出。
Session存储一个类
创建一个Person类,建立 name,age 这个属性。session不仅可以存储字符串,也能去存储一个类:
1.创建一个Person类: 此时的属性为私有属性,所以利用快捷键 ALT+ INSERT创建公共属性。
package com.AL.pojo;
public class Person {
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.在创建的Session类中,去存储一个 person 类:
package com.AL.servlet;
import com.AL.pojo.Person;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
// session。 存放一个字符串
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决乱码问题
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8"); // 使文档可以访问,还有编码
//得到一个session
HttpSession session = req.getSession();
// 给session中存放东西。 服务器对客户进行登记
session.setAttribute("name", new Person("鑫仔",1));//存储一个 person类
// 获取session的ID。 且每个客户端的sessionID是唯一的
String sessionId = session.getId();
//判断Session是否是新建的
if (session.isNew()){
resp.getWriter().write("Session创建成功,ID为"+sessionId);
}else {
resp.getWriter().write("session已经在服务器中创建了,ID为"+sessionId);
}
//Session创建的时候做了什么事情
// Cookie cookie = new Cookie("JSESSIONID", sessionId);
// resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
3.启动Tomcat测试。
Session注销
Session注销:
- 移除session信息,手动注销。
- 注销session信息。自动注销。
-
创建一个Session。
package com.AL.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; public class SessionDemo03 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); session.removeAttribute("name"); // 手动注销session session.invalidate(); System.out.println("over!!!"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
-
配置web.xml文件:
<servlet> <servlet-name>SessionDemo03</servlet-name> <servlet-class>com.AL.servlet.SessionDemo03</servlet-class> </servlet> <servlet-mapping> <servlet-name>SessionDemo03</servlet-name> <url-pattern>/s3</url-pattern> </servlet-mapping>
-
如果想要自动注销session,那么在web.xml配置文件中进行:
<!-- 设置Session默认的失效时间--> <session-config> <!-- 1分钟后Session自动失效,以分钟为单位--> <session-timeout>1</session-timeout> </session-config>
那么, 一个网站,究竟如何证明你来过 ?
- Cookie方法: 初次访问的时候,服务器给客户端一个cookie。以后客户端去请求服务端时,带着cookie去
- Session方法:客户端访问服务器的时候,服务器会登记一个Session,编号为SessionID,且这个ID是唯一的,每个浏览器是一个用户其实。用户其实是拿着SessionID去进行访问。 而在服务器中的Session是可以存放数据的。
假如两个用户去想要得到对方的数据,就需要==ServletContext,即 applicatiContext:==就好比前面的多个servlet程序中共享数据一样。
2、JSP
2.1、JSP简介
javaweb 动态web的技术栈有 JSP/Servlet。
前面我们已经创建一个Servlet程序完成了简单的动态web。
- 编写一个Servlet类。 我们选择了直接继承HttpServlet接口,就实现了继承Servlet接口。
- 将编写的Servlet发布到web服务器中。 即在web.xml里面进行注册 Servlet和Servlet的路径映射。
这里讲解使用 JSP 技术栈的动态 web。
- jsp也能完成页面跳转,提供动态数据。
什么是JSP?
Java Server Pages:Java服务器端页面,也和Servlet一样,用于动态web技术!
最大的特点:
-
写jsp就像在写HTML
-
区别:
-
- HTML只给用户提供静态的数据
- JSP页面中可以嵌入java代码,为用户提供动态数据
2.2、JSP原理
2.2.1、JSP原理解析
思路:JSP究竟是如何执行的?
-
代码层面没有任何问题
-
服务器内部工作
-
tomcat中有一个work目录;
-
在IDEA中使用Tomcat的,会在IDEA中的tomcat中产生一个work目录
-
我的电脑上的地址为:C:\Users\ASUS.IntelliJIdea2019.3\system\tomcat\Unnamed_javaweb-02_servlet\work\Catalina\localhost\r1\org\apache\jsp
在此页面下转换成了 java程序:
所以 jsp到底怎么执行?
上面的图片中可以发现, jsp 最终也会被转换成一个 java类。
我们去查看里面的代码:
//初始化
public void _JspInit(){
}
//销毁
public void _jspDestroy(){
}
//JSPService
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response){}
在这个 jspService 中的代码的内容有:
-
判断请求:
-
内置一些对象:
final javax.servlet.jsp.PageContext pageContext;//页面上下文 javax.servlet.http.HttpSession session=null; //session final javax.servlet.ServletContext application;//applicationContext final javax.servlet.ServletConfig config;//config javax.servlet.jsp.JspWriter out = null;//out final java.lang.Object page = this;//page:当前页 javax.servlet.jsp.JspWriter _jspx_out = null; //请求 javax.servlet.jsp.PageContext _jspx_page_context = null;//响应
-
输出页面前增加的代码:
response.setContentType("text/html; charset=UTF-8"); //设置响应的页面类型 pageContext = _jspxFactory.getPageContext(this, request, response, null, false, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); out = pageContext.getOut(); _jspx_out = out;
-
以上这些对象我们可以在jsp中直接使用。
-
我们在 index.jsp中输入的代码为:
<% String name = "鑫仔"; %> name:<%=name%>
-
在jsp页面中,只要是java代码就会原封不动的输出
String name = "鑫仔"; /
-
如果是html代码,就会转换为 下面的格式进行输出到前端。
out.write(" name:"); out.print(name); out.write("\n");
-
所以 JSP的本质就是一个 Servlet。浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
2.2.2、Tmocat创建Servlet类实例原理
Tomcat 容器是如何创建 Servlet 类实例?用到了什么原理?
- 当容器启动时,会读取在 webapps 目录下所有的 web 应用中的 web.xml 文件,然后对 xml 文件进行解析,并读取 Servlet 注册信息。然后,将每个应用中注册的 servlet 类都进行加载,并通过反射的方式实例化。(有时候也是在第一次请求时实例化)
- 在 Servlet 注册时加上 1 如果为正数,则在一开始就实例化,如果不写或为负数,则第一次请求实例化。
2.2.3、JSP和java、Servlet之间的关系
从前面的jsp本质上就是一个 Servlet。(自己的理解)jsp前端页面的信息,会经过转换成 *.java文件,再编译变为 *jsp.class 类。 等价于 Servlet类后, 那么这时候 原先的jsp(Servlet类)和Servlet类 会在 web容器中的 web.xml 文件被解析。 读取Servlet注册信息; 然后进行类加载 通过反射的方式实例化 Servlet 类。 有的是 在客户端第一次请求实例化 Servlet类, 然后客户端处理这个经过服务器处理完毕后的 class对象,即Servlet。
视频中的 jsp、java和Servlet的关系图:
2.2.4、Jsp 和 servlet 有什么区别
1、Jsp 经编译后就变成了 Servlet(Jsp 的本质就是 Servlet,JVM 只能识别 Java 的类,不能识别 Jsp 的代码,Web 容器将 Jsp 的代码编译成 JV M能够识别的 Java 类);
2、Jsp 更擅长表现于页面显示,servlet 更擅长于逻辑控制;
3、Servlet 中没有内置对象,Jsp 中的内置对象都是必须通过 HttpServletRequest 对象、HttpServletResponse 对象以及 HttpServlet 对象得到;
4、Jsp 是 Servlet 的一种简化,使用 Jsp 只需要完成程序员需要输出到客户端的内容,Jsp 中的 Java 脚本如何镶嵌到一个类中,由 Jsp 容器完成。而 Servlet 则是个完整的 Java类,这个类的 Service 方法用于生成对客户端的响应。
2.3、JSP基础语法和指令
-
我们可以直接在创建Maven项目的时候, 选择 一个maven模板进行创建。
-
另外一种添加webapp模板 maven项目的方法:在创建一个空的maven项目后,在下图位置处,选择添加,然后找到 web application点击添加。
添加所需要的jar包, 即导入 maven依赖:
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<groupId>com.AL</groupId>
<artifactId>javaweb-jsp</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--Servlet 依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
</dependency>
<!--JSP 依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<!--JSTL表达式的 依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2-rev-1</version>
</dependency>
<!--JSTL表达式的 依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--Standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</project>
基础语法:
任何语言都有自己的语法,JAVA中有。JSP作为java技术的一种应用,它拥有一些自己扩充的语法(了解知道即可),java所有语法都支持!需要符合java语法,所以这个<% %>这个里面的代码注释用//,<% %> 里面是用来写 java代码的 更需要符合java语法。
在jsp,嵌入java代码即可:
-
<%%>脚本片段
-
<%= %>输出变量或者表达式
-
<%! %>声明
-
<%–注释–%>
-
jsp表达式:
<%–jsp表达式 作用:将程序的输出,输出到客户端
<% = 变量或者表达式 %> --%><% = new java.util.Date() %>
注释写在这样的符号中:<%–注释 --%>
-
jsp脚本片段:
<%–jsp脚本片段–%>
<% int sum=0; for (int i = 0; i <=100 ; i++) { sum+=i; } out.println("<h1>Sum="+sum+"</h1>"); %>
<%–脚本再实现,在代码嵌入HTML元素–%>
<% for (int i = 0; i <5 ; i++) { %> <h1>hello,world</h1> <% } %>
-
jsp声明:
<%! static{ System.out.println("Loading Servlet!"); } private int globalVar =0; public void kuang(){ System.out.println("进入了方法狂!"); } %>
JSP声明会被编译到JSP生成java的类中!其他的,会被生成到JSPService方法中。即在IDEA中的tomcat文件中查看root文件里面的java代码可以发现。
我们查看启动Tomcat运行后, 在work文件中root文件中找到 jsp 下的 index_jsp.java 代码:
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent, org.apache.jasper.runtime.JspSourceImports { // JSP 的声明写在了 static{ System.out.println("Loading Servlet!"); } private int globalVar =0; public void xinxin(){ System.out.println("进入了春天!"); }
jsp的注释,不会在客户端显示。html会显示:
<!--我是 HTML的注释 -->
<%-- 我是JSP的注释--%>
写变量的时候,<%=%> 也可以写成**${}** 这样的形式。
<%-- 变量表达式
<%=%>
${} EL表达式
--%>
<%
for (int i = 0; i < 5; i++) { %>
<h1>hello,girl${i}!</h1>
<% }%>
上述三种基础语法的代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%-- $END$ --%>
<%-- JSP表达式
<% = 变量或者表达式 %> --%>
<%= new java.util.Date()%>
<br>
<%
String name = "鑫仔";
%>
name:<%=name%>
<br>
<%-- jsp 脚本片段
<% %>脚本片段 --%>
<%
int sum=0;
for (int i = 0; i <=100 ; i++) {
sum+=i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>
<br>
<%-- jsp声明 <%! %>声明--%>
<%!
static{
System.out.println("Loading Servlet!");
}
private int globalVar =0;
public void xinxin(){
System.out.println("进入了春天!");
}
%>
<br>
<%--注释--%>
<!--我是 HTML的注释 -->
<%-- 我是JSP的注释--%>
<%-- 变量表达式
<%=%>
${} EL表达式
--%>
<%
for (int i = 0; i < 5; i++) { %>
<h1>hello,girl${i}!</h1>
<% }%>
</body>
</html>
2.4、JSP指令
定制错误界面 <%@page … %>
我们在访问页面的时候,有时候会出现访问错误的界面, 如何去定制。
代码 int x =1/0; 错误代码, 因为除数不能为0. 我们定制一个错误的页面,想要在出现 500错误的时候,去跳转到一个500错误的特定信息界面。
-
设置一个出错的页面。
定义跳转路径。 表示当发生错误的时候,则页面跳转到 error/500.jsp 文件这个界面。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%-- 定制错误页面--%> <%@ page errorPage="error/500.jsp" %> <%@ page errorPage="error/404.jsp" %> <html> <head> <title>Title</title> </head> <body> <% int x=1/0; %> </body> </html>
-
自定义的500的错误的 jsp文件,
我们可以直接让此页面显示 500错误文字信息, 在这里,我们将500错误页面去换成一个图片。 扫描 web 路径下的图片。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--<h1> <h1>这个是用来设置字体大小的 <h1>自定义500错误的界面</h1> --%> <img src="../img/500.jpg" alt=""> </body> </html>
-
在web.xml中进行配置文件的修改。
—另一种方式:不用在 jsp 文件中定义跳转页面。出现了响应状态码,到对应的jsp页面。
我们也可以直接在 web.xml文件中进行配置修改:这样出现了错误,就直接去跳转到对应的jsp文件执行。
<?xml version="1.0" encoding="UTF-8"?> <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_4_0.xsd" version="4.0"> <!-- 配置对静态资源的处理 --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <!-- 自定义配置错误页面--> <error-page> <error-code>404</error-code> <location>/error/404.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/error/500.jsp</location> </error-page> </web-app>
-
启动,进行测试。
文件夹格式:
页面拼接
JSP指令:
<%@page … %>
<%@>
- <jsp:include page="/common/header.jsp" />
- <%@include file=“common/header.jsp”%>
测试指令**<%@include … %>**:拼接指令。
-
创建两个jsp文件。 header.jsp 和footer.jsp文件:,且这两个 jsp文件建立在 web目录下的common文件中。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <h1>我是header</h1> <html> <head> <title>Title</title> </head> <body> </body> </html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <h1>我是footer</h1> <html> <head> <title>Title</title> </head> <body> </body> </html>
-
定义一个 jsp3.jsp文件。 想要去展现拼接两个页面的结果。**<%@include … %>**指令
<%--JSP的注释--%> <!--HTML的注释--> <%--两个页面拼接在一起: 合二为一--%> <%@include file="common/header.jsp"%> <h1>网页主体</h1> <%@include file="common/footer.jsp"%> <hr>
-
采用**jsp:include 指令**进行页面拼接。 斜杠 / 表示外部的路径。
<%--两个页面拼接在一起: 单独存在,页面进行拼接--%> <jsp:include page="/common/header.jsp" /> <h1>网页主体</h1> <jsp:include page="/common/footer.jsp" />
-
启动tomcat,进行测试观察者这两种方式的结果。http://localhost:8080/jsp3.jsp
粗略的看,这两种指令 @include 和 jsp.include 完成的效果一样。 但还是存在着一些区别。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--JSP的注释--%> <!--HTML的注释--> <%--两个页面拼接在一起: 合二为一--%> <%@include file="common/header.jsp"%> <h1>网页主体</h1> <%@include file="common/footer.jsp"%> <hr> <%--两个页面拼接在一起: 单独存在,页面进行拼接--%> <jsp:include page="common/header.jsp" /> <h1>网页主体</h1> <jsp:include page="common/footer.jsp" /> </body> </html>
@include 是将两个页面合二为一;jsp:include是将页面进行拼接。
2.5、JSP内置对象及作用域
2.5.1、9大内置对象
- PageContext 存东西
- Request 存东西,封装客户端的请求。 包括来自get和post请求的参数
- Response 封装服务器对客户端的响应。
- Session 存东西。 封装用户会话的对象
- Application [ServletContext] 存东西 封装服务器运行环境的 对象
- conifg [ServletConfig] Web应用的配置对象
- out
- page Jsp 页面本身(相当于 Java 程序中的 this);
- exception
例子: pageContextDemo01.jsp
使用存放东西的这几个内置对象: pageContext、request、session、 application 去存放数据。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 内置对象
在脚本片段的代码,会原封不动生成.jsp.java 要遵循java语法
--%>
<%
pageContext.setAttribute("name1","鑫仔1号");//保存的数据只在一个页面中有效
request.setAttribute("name1","鑫仔2号");//保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name1","鑫仔3号");//保存的数据只在一次会话中有效,从打开浏览器道关闭浏览器
application.setAttribute("name1","鑫仔4号");//保存的数据只在服务器中有效,从打开服务器道关闭服务器
%>
<% //从pageContext取出,我们通过寻找的方式来
//作用域:从底层到高层的顺序
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5");
%>
<%--使用EL表达式输出 形式为:${}--%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
</body>
</html>
保存的数据,作用的区域不同,从==底层到高层的作用域分别为:page、request(请求)、session(会话)、application==
pageContext.setAttribute("name1","鑫仔1号");//保存的数据只在一个页面中有效
request.setAttribute("name1","鑫仔2号");//保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name1","鑫仔3号");//保存的数据只在一次会话中有效,从打开浏览器道关闭浏览器
application.setAttribute("name1","鑫仔4号");//保存的数据只在服务器中有效,从打开服务器道关闭服务器
新建一个 pageContextDemo02.jsp.
查看哪个有效? 因为作用域不同,存活的时间也是不一样的。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<% //从pageContext取出,我们通过寻找的方式来
//作用域:从底层到高层的顺序
String name1 = (String) pageContext.findAttribute("name1");
String name2 = (String) pageContext.findAttribute("name2");
String name3 = (String) pageContext.findAttribute("name3");
String name4 = (String) pageContext.findAttribute("name4");
String name5 = (String) pageContext.findAttribute("name5");
%>
<%--使用EL表达式输出 形式为:${}--%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name5}</h3>
</body>
</html>
当我们从 pageContext取出时, 我们通过寻找的方式来。即pageContext.findAttribute()方法。
作用域的顺序为: page->request -> session ->application。类似于JVM中的双亲委任机制。
双亲委任机制: 先找最大,级别最高的,一开始就继承的那个类。 没有了再从高往低找。
2.5.2、JSP的4种作用域
Jsp 中的四种作用域包括 page、request、session 和 application,具体来说:
1、page 代表与一个页面相关的对象和属性;
2、request 代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多
个页面,涉及多个 Web 组件,需要在页面显示的临时数据可以置于此作用域;
3、session 代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关
的数据应该放在用户自己的 session 中;
4、application 代表与整个 Web 应用程序相关的对象和属性,它实质上是跨越整个 Web
应用程序,包括多个页面、请求和会话的一个全局作用域。
对应于上面这4种作用域,
- pageContext的范围只适用于当前页面范围,超过这个范围就不行了。 所以不能使用pageContext去进行页面之间的参数传递。
- request:用户向服务端发送请求,服务端响应后的数据。用户看完就没用了。 即作用域的范围是 在这一JSP网页 请求到另一 JSP网页之间,然后属性就会消失。 比如:新闻,用户看完后就失效了
- session:客户端向用户端发送请求,产生的数据。 用户进行使用,会使用一定的时间。 但是当与服务端关闭后,即关闭浏览器,则就没用了。
- application:客户端向服务端发送请求,产生的数据。 这个用户用完,其它用户还能使用。 范围在服务器一开始执行服务,到服务器关闭为止。它的范围最大,生存周期最长。
不同的作用域它们之间的关系:
2.6、jsp标签、jstl标签、EL表达式
在使用这些标签的时候,需要相应的 jar包。
在 pom.xml文件中 导入maven依赖:
<!--JSTL表达式的 依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2-rev-1</version>
</dependency>
<!--JSTL表达式的 依赖 -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--Standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</project>
EL表达式: ${}
- 获取数据
- 执行运算
- 获取web开发的常用对象
我们使用美元符号大括号进行 获取数据和执行运算。
2.6.1、jsp标签
jsp:forward page 页面跳转标签。
-
在jsptag.jsp中写入一个程序,并指定跳转页面。 去观察跳转的结果。
定义一个页面,功能就是用来跳转的,并给这个页面一些数据信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>1</h1> <%--jsp:include jsp标签--%> <%--页面跳转标签 jsp:forward page --%> <jsp:forward page="jsptag2.jsp"> <jsp:param name="name" value="ALZN"/> <jsp:param name="age" value="18"/> </jsp:forward> </body> </html>
-
对应的跳转页面 jsptag2.jsp。 利用request.getParameter() 去获取信息。
功能是用来得到来自跳转页面的信息。用来展示信息的:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>2</h1>
<%--取出参数
<%=变量名%> <${}> 这两种方式等价
--%>
<%--取出参数--%>
名字:<%=request.getParameter("name")%>
年龄:<%=request.getParameter("age")%>
</body>
</html>
获取参数的两种方式:
- =变量名
- ${}
3.这种 jsp 标签页面跳转。 是不需要像 Servlet程序那样进行 web发布的。 直接启动Tomcat进行测试就行了。
输入:http://localhost:8080/jsptag.jsp 结果为:
可以发现, 我们定义的 jsptag.jsp 页面就是会直接发生跳转,响应到 jsptag2.jsp的信息。但是url路径却没变。
2.6.2、JSTL标签
关于JSTL标签的简单使用链接:https://www.runoob.com/jsp/jsp-jstl.html
JSTL表达式:
- JSTL标签库的使用是为了弥补HTML标签的不足
- 自定义许多标签,供我们使用,
- 标签的功能和 java 代码一样。
JSTL标签:
- 核心标签
- 格式化标签
- SQL标签
- XML标签
核心标签是最常用的 JSTL标签。引用核心标签库的语法如下:
<%@ taglib prefix=“c” uri=“http://java.sun.com/jsp/jstl/core” %>
标签 | 描述 |
---|---|
<c:ount> | 用于在JSP中显示数据,就像<%= … > |
<c:set> | 用于保存数据 |
<c:remove> | 用于删除数据 |
<c:catch> | 用来处理产生错误的异常状况,并且将错误信息储存起来 |
<c:if> | 与我们在一般程序中用的if一样 |
<c:choose> | 本身只当做<c:when>和<c:otherwise>的父标签 |
<c:when> | <c:choose>的子标签,用来判断条件是否成立 |
<c:otherwise> | <c:choose>的子标签,接在<c:when>标签后,当<c:when>标签判断为false时被执行 |
<c:import> | 检索一个绝对或相对 URL,然后将其内容暴露给页面 |
<c:forEach> | 基础迭代标签,接受多种集合类型 |
<c:forTokens> | 根据指定的分隔符来分隔内容并迭代输出 |
<c:param> | 用来给包含或重定向的页面传递参数 |
<c:redirect> | 重定向至一个新的URL. |
<c:url> | 使用可选的查询参数来创造一个URL |
JSTL标签库使用步骤:
- 引入对应的 taglib
- 使用其中的方法
- 在Maven中也需要引入 jstl 的包,否则就会报错: JSTL解析错误。
例子:
在coreif.jsp文件下:
-
导入对应的taglib: 这个和前面的 <%@ include 类似。
- 引入JSTL核心标签库, 我们才能去使用JSTL标签 core;
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
-
使用其中的方法: <c:if>。 这里面的代码形式和 java代码一样。
if代码测试:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%-- 引入JSTL核心标签库, 我们才能去使用JSTL标签 core--%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> </head> <body> <h4>if测试</h4> <hr> <%--使用EL表达式获取表单中的数据 ${param.参数名} --%> <form action="coreif.jsp" method="get"> <input type="text" name="username" value="${param.username}"> <input type="submit" value="登录"> </form> <%--判断 如果用户提交的是管理员,则登录成功--%> <c:if test="${param.username == 'admin'}" var="isAdmin"> <c:out value="管理员欢迎您!"></c:out> </c:if> </body> </html>
corewhen.jsp文件下测试 jstl标签库中的 <c:when>, 条件判断是否成立。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--定义一个变量score,值为85--%>
<c:set var="score" value="55"/>
<c:choose>
<c:when test="${score>=90}">
你的成绩为优秀
</c:when>
<c:when test="${score>=80}">
你的成绩为一般
</c:when>
<c:when test="${score>=70}">
你的成绩为良好
</c:when>
<c:when test="${score<=60}">
你的成绩为不及格
</c:when>
</c:choose>
</body>
</html>
coreforeach.jsp文件下测试:<c:forEach>。 进行遍历:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.ArrayList" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
ArrayList<String> people = new ArrayList<>();
people.add(0,"张三");
people.add(1,"李四");
people.add(2,"王五");
people.add(3,"赵六");
people.add(4,"田七");
request.setAttribute("list",people);
%>
<%--
var , 每一次遍历出来的变量
items, 要遍历的对象
begin, 哪里开始
end, 到哪里
step, 步长
--%>
<c:forEach var="people" items="${list}">
<c:out value="${people}"/> <br>
</c:forEach>
<hr>
<c:forEach var="people" items="${list}" begin="1" end="3" step="1" >
<c:out value="${people}"/> <br>
</c:forEach>
</body>
</html>
3、JavaBean
实体类
JavaBean有特定的写法:
- 必须要有一个无参构造
- 属性必须私有化
- 必须有对应的get/set方法
一般用来和数据库的字段做映射 ORM;
ORM:对象关系映射
- 表 —> 类
- 字段 —> 属性
- 行记录 —> 对象
people表:
id | name | age | address |
---|---|---|---|
1 | 鑫仔1号 | 1 | 山西 |
2 | 鑫仔2号 | 2 | 山西 |
3 | 鑫仔3号 | 3 | 山西 |
这个表去对应位一个类的话:
class People{
private int id;
private String name;
private String adress
}
class A{
new People(1,"鑫仔1号",1,"山西");
new People(2,"鑫仔2号",2,"山西");
new People(3,"鑫仔3号",3,"山西");
}
JavaBean 例子:
-
people类 java程序。
属性私有化:即 private, 这种属性子类不能直接继承,需要get/set方法去将属性创建为一些公共属性去进行调用。
package com.AL.pojo; public class people { private int id; private String name; private int age; private String address; public people() { } public people(int id, String name, int age, String address) { this.id = id; this.name = name; this.age = age; this.address = address; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "people{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", address='" + address + '\'' + '}'; } }
-
创建数据库。 数据库为jdbc,表名为people:
-
创建javabean.jsp文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%--<br>换行 <hr>是html标签 表示一条直线 --%> <jsp:useBean id="people" class="com.AL.pojo.people" scope="page"/> <jsp:setProperty name="people" property="address" value="秦皇岛"/> <jsp:setProperty name="people" property="id" value="1"/> <jsp:setProperty name="people" property="age" value="18"/> <jsp:setProperty name="people" property="name" value="鑫仔"/> 姓名:<jsp:getProperty name="people" property="name"/> 年龄:<jsp:getProperty name="people" property="age"/> id:<jsp:getProperty name="people" property="id"/> 地址:<jsp:getProperty name="people" property="address"/> </body> </html>
启动Tomcat进行测试:http://localhost:8080/javabean.jsp
4、MVC三层架构
什么是MVC:Model View Controller 模型、视图、控制器
4.1、以前的架构
用户直接访问控制层,控制层就可以直接操作数据库;
就好比,我们前面创建的一个javaweb的 Servlet程序+jsp。 不过jsp主要是用来渲染界面的,虽然本质上也是一个Servlet。 客户端访问服务端,我们在Servlet程序中接收到请求 req, 然后回响应 resp。而当加入数据库后,直接在Servlet代码中进行 JDBC的工作,处理数据库的数据, 然后把操作得到的数据返回给客户端,并且你改了数据还要在服务端中对数据库完成同步 数据持久化。 代码臃肿,不利于维护。
servlet–CRUD–>数据库
弊端:程序十分臃肿,不利于维护 (要在Servlet里面写JDBC的代码)
servlet的代码中:处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码
架构:没有什么是加一层解决不了的!
程序猿调用
|
JDBC (实现该接口)
|
Mysql Oracle SqlServer …(不同厂商)
4.2、MVC三层架构
改进:MVC架构如下所示, Model、View、Controller
三层架构中,各自主要负责的功能为:
Model
- 业务处理 :业务逻辑(Service)
- 数据持久层:CRUD (Dao - 数据持久化对象)
View
- 展示数据
- 提供链接发起Servlet请求 (a,form,img…)
Controller (Servlet):
- 接收用户的请求 :(req:请求参数、Session信息….)
- 交给业务层处理对应的代码
- 控制视图的跳转
- 登录—>接收用户的登录请求—>处理用户的请求(获取用户登录的参数,username,password)---->交给业务层处理登录业务(判断用户名密码是否正确:事务)—>Dao层查询用户名和密码是否正确–>数据库
在MVC三层架构中, 我们不再让Servlet独自一人完成刚才的 请求、响应、视图跳转、JDBC、业务代码等工作。
- 我们让Servlet程序 作为一个控制器 Controller,处理请求,然后去调用Model中的 service层进行业务处理,响应完成后去调用 view 视图层进行视图跳转。
- View专心的渲染视图,展现给用户页面; 并且接收客户端的链接 去发送请求
- Model 模型中分为 Service 业务层专门进行业务逻辑处理; Dao层进行底层的数据库处理,完成数据持久化。
5、过滤器 Filter
5.1、Filter
Filter:过滤器,用来过滤网站的数据;
- 处理中文乱码
- 登陆验证
5.2、写过滤器
-
创建maven项目。导入maven依赖,这里特地增加了 数据库连接的依赖。
<?xml version="1.0" encoding="UTF-8"?> <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.0</modelVersion> <groupId>com.AL</groupId> <artifactId>javaweb-filter</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--Servlet 依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>3.0-alpha-1</version> </dependency> <!--JSP 依赖 --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> </dependency> <!--JSTL表达式的 依赖 --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl-api</artifactId> <version>1.2-rev-1</version> </dependency> <!--JSTL表达式的 依赖 --> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!--Standard标签库 --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- 连接数据库--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies> </project>
-
编写过滤器 filter类。
-
我们想要去进行过滤所有的代码,让其进行编码 UTF-8。 新建一个 CharacterEncodingFilter 类。
-
注意:此时的过滤器导入的包为 java.servlet.* 。
-
package com.AL.filter; import javax.servlet.*; import java.io.IOException; public class CharacterEncodingFilter implements Filter { // 初始化: web服务器启动,就已经初始化了,随时等待过滤对象出现 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("CharacterEncodingFilter初始化"); } //Chain:链 /* * 1.过滤中的所有代码,在过滤特定请求的时候都会执行 * 2.必须要让过滤器继续同行 * chain.doFilter(request,response); * */ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println("CharacterEncodingFilter执行前"); filterChain.doFilter(servletRequest,servletResponse); //让我们的请求继续走,如果不写的话,程序到这里就被拦截停止 System.out.println("CharacterEncodingFilter执行后"); } // 销毁: web服务器关闭的时候,过滤器就会被销毁 public void destroy() { System.out.println("CharacterEncodingFilter销毁"); } }
-
-
编写Servlet类。
新建一个showFilter,servlet程序。添加编码和没有编码,分别进行调试:
注意:如果有1000个servlet程序响应, 那么我们就要输1000次编码 utf-8。 所以我们想要过滤器去做这件事情。
package com.AL.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 ShowServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); resp.getWriter().write("你好,李焕英!"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
-
编写web.xml配置文件.
-
注册Servlet类和 Servlet的映射路径。定义两种 添加编码和没有编码,分别进行调试: 即一种
-
过滤器 filetr的注册和映射路径。
-
<?xml version="1.0" encoding="UTF-8"?> <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_4_0.xsd" version="4.0"> <servlet> <servlet-name>ShowServlet</servlet-name> <servlet-class>com.AL.servlet.ShowServlet</servlet-class> </servlet> <servlet-mapping> <!--经过了 过滤器filter的 servlet程序(ShowFilter)--> <servlet-name>ShowServlet</servlet-name> <url-pattern>/servlet/show</url-pattern> </servlet-mapping> <servlet-mapping> <!--正常情况下的 servlet程序(ShowFilter)--> <servlet-name>ShowServlet</servlet-name> <url-pattern>/show</url-pattern> </servlet-mapping> <!-- 过滤器的配置--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.AL.filter.CharacterEncodingFilter</filter-class> </filter> <!-- 只要是/servlet的任何请求,都会经过这个过滤器--> <!-- <url-pattern>/*</url-pattern> --> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/servlet/*</url-pattern> </filter-mapping> </web-app>
-
启动Tomcat进行测试。
- 没有经过过滤器 filter的servlet程序。 输入 localhost:8080/show.结果为:
- 经过过滤器 filter的servlet程序。 输入 **localhost:8080/servlet/show.**结果为:
设计一个过滤器的步骤:
- 编写一个过滤器 filetr类。实现Filter接口。
- web.xml配置文件中注册过滤器。
在 servlet程序和服务器之间添加一些过滤器,完成请求和响应的一些功能,解决乱码和过滤不必要的请求。
6、监听器
实现一个监听器的接口;(有N种接口)
- 编写一个监听器。 即实现一个监听器的接口就行。
- web.xml文件中注册监听器
例子:
统计网站在线人数。
-
编写一个 session的监听器程序。 在服务器中存储这种 网站在线人数的信息, 不存放在 cookie里面。
-
创建session监听:每次创建session,就触发httpSessionEvent 事件。观察得到的ID
-
销毁session监听:
package com.AL.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class OnlineCountListener implements HttpSessionListener { //创建 session监听: 查看你的一举一动 // 一旦创建了 Session就会触发一次这个事件 public void sessionCreated(HttpSessionEvent httpSessionEvent) { ServletContext ctx = httpSessionEvent.getSession().getServletContext(); System.out.println(httpSessionEvent.getSession().getId()); Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount"); if (onlineCount == null){ onlineCount = new Integer(1); }else { int count = onlineCount.intValue(); onlineCount = new Integer(count+1); } ctx.setAttribute("OnlineCount", onlineCount); } //销毁session监听 //一旦销毁Session就会触发一次这个事件! public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { ServletContext ctx = httpSessionEvent.getSession().getServletContext(); Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount"); if (onlineCount == null){ onlineCount = new Integer(1); }else { int count = onlineCount.intValue(); onlineCount = new Integer(count-1); } ctx.setAttribute("OnlineCount", onlineCount); } }
-
-
在index.jsp中去获得在线人数的数据,用于界面展示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> <h1>当前有 <span><%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%></span>人在线</h1> </body> </html>
-
配置文件web.xml监听事件的注册:
<!-- 注册监听器--> <listener> <listener-class>com.AL.listener.OnlineCountListener</listener-class> </listener>
-
添加测试:查看是有几个,具体标号
//查看具体标号 System.out.println(httpSessionEvent.getSession().getId());
多开几个浏览器进行测试。此时java控制台显示的3个人的标号 getId. 三个人在线。
E94BC8A2E7DF88FE4397B8A0D0C032E4
DD3304FD19601E9BC73FF08F3AE96B81
123623BDC7FAE4355487EEEE0F801047
session销毁有自动和手动两种方式,如下所示:
-
手动销毁
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { ServletContext ctx = httpSessionEvent.getSession().getServletContext(); httpSessionEvent.getSession().invalidate();//手动销毁
-
自动销毁
<!-- 手动销毁session--> <session-config> <session-timeout>1</session-timeout> </session-config>
7、监听器和过滤器的常见应用
7.1、监听器GUI中理解
监听事件的例子:
package com.AL.listener;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
//监听事件的例子
public class TestPanel {
public static void main(String[] args) {
Frame frame = new Frame("中秋节快乐"); //新建一个窗体
Panel panel = new Panel(null); //面板
frame.setLayout(null); //设置窗体的布局
frame.setBounds(300,300,500,500);
frame.setBackground(new Color(0,0,255)); //设置背景颜色
panel.setBounds(50,50,300,300);
panel.setBackground(new Color(0,255,0)); //设置背景颜色
frame.add(panel);
frame.setVisible(true);
//监听事件,监听关闭事件
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
}
});
}
}
7.2、Filter实现权限拦截
- 用户登录之后才能进入主页。
- 用户注销后不能进入主页。
1.登录界面 login.jsp。
在这里定义登录界面, 使用 post方法去获取页面前端参数。 请求路径为 /servlet/login。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录</h1>
<form action="/servlet/login" method="post">
<input type="text" name="username">
<input type="submit">
</form>
</body>
</html>
2.创建一个 servlet程序。
获取前端的数据后,进行重定向,实现页面跳转。 方法和前端处的一样为 post。
package com.AL.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 LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前端请求的参数
String username = req.getParameter("username");
if (username.equals("admin")){ //登录成功
req.getSession().setAttribute("USER_session", req.getSession().getId());
resp.sendRedirect("/sys/success.jsp");
} else { //登录失败
resp.sendRedirect("/error.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
3.定义登录成功和失败的 jsp页面。
注意路径,success.jsp在 sys目录下。 error.jsp在同一级目录下。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>主页</h1>
<p><a href="/servlet/logout">注销</a> </p>
</body>
</html>
error.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>错误</h1>
<h3>没有权限,用户名错误</h3>
<a href="login.jsp">返回登录界面</a>
</body>
</html>
4.web.xml配置文件。
<!-- 登陆页面和注销页面的 Servlet注册-->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.AL.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/servlet/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>com.AL.servlet.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/servlet/logout</url-pattern>
</servlet-mapping>
启动Tomcat进行测试:在浏览器中输入 localhost:8080/login.jsp, 然后在接收到请求后,即提交动作 submit会 会在web.xml文件中找到此Servlet的注册信息去进行 servlet ,对前端客户端的信息进行获取,然后去响应 进行重定向 页面跳转。
成功进入登录页面:
在用户名错误的时候:
无法登录成功.
但是在测试的时候,你直接输入http://localhost:8080/sys/success.jsp 也会直接进入 登录成功的页面。 我们要使用过滤器 去阻止这种操作。 页面拦截的作用、
5.过滤器拦截。
对于登录成功的页面:/sys/success.jsp 这个界面。 我们设置了一个 USER_SESSION 去获取 session的ID, 当ID==null的时候,这说明没有进行页面登录中进行登录成功的 事件, 所以会直接拦截,让其去跳转到 错误页面。
package com.AL.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SysFilter implements Filter {
// 初始化: web服务器启动,就已经初始化了,随时等待过滤对象出现
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter初始化");
}
//SysFilter过滤器
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
if (request.getSession().getAttribute("USER_SESSION") == null) {
response.sendRedirect("/error.jsp");
}
chain.doFilter(request, response);
}
// 销毁: web服务器关闭的时候,过滤器就会被销毁
public void destroy() {
System.out.println("CharacterEncodingFilter销毁");
}
}
在拦截器 Servlet接口实现类的步骤:
- 初始化。public void init(FilterConfig filterConfig) throws ServletException{} 在web服务器启动的时候,就会初始化,然后去随时等待过滤对象出现
- 过滤器。doFilter。 此时的过滤器 拦截器作用是 sessiID为空的时候,就让其去跳转到错误界面
- ==销毁。destroy() 。==web服务器关闭的时候,过滤器就会被销毁
6.过滤器的web.xml配置文件信息。
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>com.AL.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
启动Tomcat进行测试,直接输入:localhost:8080/sys/success.jsp 发现此时无法将纳入登录成功的页面:
8、JDBC
简单的来说 JDBC就是一个统一驱动, 用于 java去连接 数据库驱动。
我们在 mysql数据库学习中, 在IDEA中去进行JDBC练习时,导入的jar包有:
需要jar包的支持:
- java.sql
- javax.sql
- mysql-conneter-java… 连接驱动(必须要导入)
在这里,我们使用Maven,创建 maven项目后,直接导入 maven的依赖即可:
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
创建数据库:
CREATE TABLE `users` (
`id` INT(11) NOT NULL,
`name` VARCHAR(40) DEFAULT NULL,
`password` VARCHAR(40) DEFAULT NULL,
`email` VARCHAR(40) DEFAULT NULL,
`birthday` DATE DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
向其中添加几组数据: 例子:
-- 注意,在进行创建数据库的时候, 关于 列表名 column 要使用 飘号进行包裹, 而不是单引号,
-- 因为在这里的意义不是字符串,而是属性段
INSERT INTO `users`(`id`,`name`,`password`,`email`,`birthday`)
VALUES('3','坤坤','123456','kunkun@qq.com','2021-1-1'),('4','略略','123456','luelue@qq.com','2021-1-1')
INSERT INTO `users`(`id`,`name`,`password`,`email`,`birthday`)
VALUES('5','坤坤','123456','kunkun@qq.com','2021-1-1');
INSERT INTO `users`(`id`, `name`, `password`, email, birthday)
VALUES(6,'呜呜','123456','wuwu@qq.com','2021-1-1');
8.1、JDBC的步骤和执行SQL的对象 Statement、PreparedStatement
JDBC的步骤,整个流程:
- 加载驱动
- 连接数据库,代表数据库
- 向数据库发送SQL的对象Statement : CRUD
- 编写SQL (根据业务,不同的SQL)
- 执行SQL
- 关闭连接(先开的后关)
普通的SQL执行对象 Statement:
- Statement statement = connection.createStatement(); 创建一个去执行SQL的对象。 简单来说,就是把 sql语句丢给这个对象 statement里面去执行。
- 查询使用executeQuery. 增删改使用executeUpdate()
package com.AL.test;
import java.sql.*;
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 数据库的配置信息
// useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库, 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 3. 向数据库发送 SQL的对象 Statement: CRUD. 用这个对象去完成 操作CRUD
Statement statement = connection.createStatement();
// 4.编写 SQL语句
String sql = "select * from users";
// 5.使用 statement 即能够执行sql的对象 去 进行具体的sql语句。 查询语句返回的是一个结果集: ResultSet
ResultSet rs = statement.executeQuery(sql); // 查询使用executeQuery. 增删改使用executeUpdate()
while (rs.next()){
System.out.println("id="+rs.getObject("id"));
System.out.println("name="+rs.getObject("name"));
System.out.println("password="+rs.getObject("password"));
System.out.println("email="+rs.getObject("email"));
System.out.println("birthday="+rs.getObject("birthday"));
}
// 6.关闭连接,释放资源。 遵循先开后关的原则
rs.close();
statement.close();
connection.close();
}
}
采用预编译的方法。
- 即使用占位符 ?的 方式去进行编译 sql语句。
- 使用 PreparedStatement preparedStatement = connection.prepareStatement(sql);
package com.AL.test;
import java.sql.*;
public class TestJDBC2 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 数据库的配置信息
// useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库, 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// 3. 编写 SQL。 使用占位符 ?
String sql = "insert into users(`id`, `name`, `password`, `email`, `birthday`) values(?,?,?,?,?);";
// 4. 预编译. 向数据库发送 SQL的对象 PreparedStatement: CRUD. 用这个对象去完成 操作CRUD
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,7); //给第一个占位符?的赋值为 1;
preparedStatement.setString(2, "乌日三省吾身");
preparedStatement.setString(3,"787878");
preparedStatement.setString(4,"1356207897@qq.com");
preparedStatement.setString(5, String.valueOf(new Date(new java.util.Date().getTime())));
// 5.使用 preparedStatement 即能够执行sql的对象 去 进行具体的sql语句。
// 查询语句返回的是一个结果集: ResultSet.查询使用executeQuery.
// 增删改使用executeUpdate(). 返回的是一个
int i = preparedStatement.executeUpdate();
if (i>0) System.out.println("插入成功");
// 6.关闭连接,释放资源。 遵循先开后关的原则
preparedStatement.close();
connection.close();
}
}
8.2、JDBC事务
事务的性质: ACID原则:原子性、一致性、隔离性、持久性。
事务:
- 要么都成功,要么都失败!
- ACID原则:保证数据的安全。
事务完成的步骤:
- 开启事务
- 事务提交 commit()
- 事务回滚 rollback()
- 关闭事务
需要导入的jar包: Junit单元测试
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
简单使用
@Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!
@Test
public void test(){
System.out.println("Hello");
}
搭建一个环境去设计事务: 银行转账
创建数据库:
-- 创建账单 account 数据表
CREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET = utf8
INSERT INTO `account`(`name`,`money`)
VALUES ('A',2000.00),('B',1000);
-- 此时输入的A是字符串的意思,并不是表名,所以用单引号,不用`。
JDBC程序:
- 数据库配置信息,加载驱动
- 连接数据库,
- 创建能够代表数据库去执行SQL的对象 Statement:CRUD
- 编写 SQL语句
- 执行SQL
- 关闭连接。
但是需要添加事务回滚 rollback, 所以采用 try catch方法去进行判断:事务失败则回滚,
package com.AL.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJDBC3 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 数据库的配置信息
// useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库, 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
// // 3. 向数据库发送 SQL的对象 Statement: CRUD. 用这个对象去完成 操作CRUD
// Statement statement = connection.createStatement();
try {
// 3.通知数据库开启事务, false开启
connection.setAutoCommit(false);
String sql = "update account set money = money-1000 where name='A';";
connection.prepareStatement(sql).executeUpdate();
// 制造错误
//int i =1/0;
String sql2 = "update account set money = money-200 where name='B';";
connection.prepareStatement(sql2).executeUpdate();
connection.commit(); //以上两条SQL都执行成功了,就提交事务
System.out.println("success");
} catch (Exception e) {
try {
//如果出现异常,就通知数据库回滚事务
connection.rollback();
}catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}