马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
Servlet
什么是Servlet?
Servlet生命周期
多线程处置处罚
Servlet处置处罚的根本流程
Servlet步伐实现
Servlet对象的工作原理及其生命周期、service()方法
service()方法
Servlet对象的共享变量
通过JSP页面访问servlet
doGet()方法和doPost()方法
Servlet跳转
1.客户端跳转(重定向):地点栏会跳转
2.服务器端跳转(哀求转发):地点栏不会跳转
利用session
Servlet转达参数到JSP ---利用session
Servlet转达参数到JSP ---利用request
JSP与数据库访问
JDBC
JDBC数据库举行交互
DriverManager类
创建Statement对象
Statement接口常用方法
ResultSet接口
查询操纵
处置处罚查询效果的方法
含糊查询
更新、添加与删除操纵
事件
Servlet
Servlet简介
- Servlet是利用Java语言编写的服务器端步伐,可以像JSP一样天生动态的WEB页。
- Servlet紧张运行在服务器端,并由服务器调用实行,是一种按照Servlet尺度开发的类。
- Servlet接纳了多线程的处置处罚方式,并生存了Java的可移植性特点,使得Servlet更易利用且功能更加强大。
什么是Servlet?
Servlet是一个Java编程语言中的接口,紧张用于扩展服务器的功能。Servlet可以用来处置处罚HTTP哀求,并返反相应给客户端。它们常用于构建动态Web应用步伐。
- import javax.servlet.*;
- import java.io.*;
- public class HelloWorldServlet extends GenericServlet {
- public void service(ServletRequest request, ServletResponse response)
- throws ServletException, IOException {
- // 设置响应内容类型为文本/html
- response.setContentType("text/html");
-
- PrintWriter out = response.getWriter();
- out.println("<html>");
- out.println("<body>");
- out.println("<h1>Hello, World!</h1>");
- out.println("</body>");
- out.println("</html>");
- }
- }
复制代码 上面的代码展示了一个简单的HelloWorldServlet,它继承自GenericServlet,并实现了service方法。在这个方法里,我们设置了相应的内容范例为text/html,然后通过getWriter()获取到一个PrintWriter对象,末了向客户端发送一个简单的HTML字符串。
Servlet生命周期
Servlet的生命周期包罗加载、初始化、服务、烧毁四个阶段。
- 加载:当服务器启动大概第一次吸收到对某个Servlet的哀求时,会加载该Servlet。
- 初始化:加载完成后,服务器会调用Servlet的init()方法举行初始化操纵。
- 服务:当服务器吸收到客户端的哀求后,会调用Servlet的service()方法处置处罚哀求并产生相应。
- 烧毁:当服务器关闭大概Servlet不再利用时,服务器会调用Servlet的destroy()方法开释资源。
多线程处置处罚
由于Servlet是在服务器端运行的,以是它可以同时处置处罚多个客户端的哀求。这意味着Servlet必须可以大概处置处罚并发环境,因此Servlet默认就是线程安全的。
- import javax.servlet.*;
- import java.util.concurrent.atomic.AtomicInteger;
- public class CounterServlet extends HttpServlet {
- private AtomicInteger counter = new AtomicInteger(0);
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- int currentCount = counter.incrementAndGet();
- resp.getWriter().println("Current count is " + currentCount);
- }
- }
复制代码 Servlet处置处罚的根本流程
- 客户端(通常是Web欣赏器)通过HTTP协议提出哀求。
- Web服务器吸收该哀求并将它转发给相应的Servlet。
- 如果Servlet尚未加载,Web服务器将其加载到Java捏造机并实行。
- Servlet吸收HTTP哀求并实行某些处置处罚。
- Servlet天生相应内容并将其传回给服务器。
- 服务器将从Servlet收到的相应返回给客户端。
- import javax.servlet.*;
- import java.io.*;
- public class HelloServlet extends GenericServlet {
- @Override
- public void service(ServletRequest request, ServletResponse response)
- throws ServletException, IOException {
- // 设置响应内容类型为文本/html
- response.setContentType("text/html");
- // 获取输出流
- PrintWriter out = response.getWriter();
- // 输出响应内容
- out.println("<html>");
- out.println("<body>");
- out.println("<h1>Hello, Servlet</h1>");
- out.println("</body>");
- out.println("</html>");
- }
- }
复制代码 在这个例子中,我们创建了一个名为HelloServlet的Servlet,它继承自GenericServlet。当服务器吸收到哀求并转发给这个Servlet时,它会调用service()方法。在这个方法内,我们设置了相应的内容范例为text/html,然后通过getWriter()获取到一个PrintWriter对象,末了向客户端发送一个简单的HTML字符串。
为了使这个Servlet可以大概在服务器上运行,我们必要在Web应用的摆设形貌符(通常为web.xml)中设置它
- <servlet>
- <servlet-name>hello</servlet-name>
- <servlet-class>com.example.HelloServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>hello</servlet-name>
- <url-pattern>/hello</url-pattern>
- </servlet-mapping>
复制代码 这段XML设置告诉服务器,当吸收到以/hello末了的URL哀求时,应该调用HelloServlet来处置处罚。
如今,如果你在欣赏器中输入http://yourserver.com/hello,服务器就会加载并实行HelloServlet,然后将效果返回给你。这就是Servlet处置处罚哀求的根本流程
Servlet步伐实现
在整个Servlet步伐之中最紧张的就是Servlet接口,在此接口下界说了一个GenericServlet的子类,但是一样平常不会直接继承此类,而是根据所利用的协议选择GenericServlet的子类继承,比方:如今是接纳HTTP协议处置处罚的,以是一样平常而言当必要利用HTTP协议操纵时用户自界说的Servlet类都要继承HttpServlet类。
- Servlet接口:这是全部Servlet的底子,界说了Servlet的焦点活动。
- GenericServlet:这是一个抽象类,实现了Servlet接口,提供了通用的Servlet功能,但一样平常不直接利用。
- HttpServlet:这是GenericServlet的一个子类,专门针对HTTP协议举行了优化,大部门环境下,用户自界说的Servlet都会继承此类。
- 用户自界说Servlet:在此底子上,我们可以根据需求创建自己的Servlet类。
怎样实现一个简单的Servlet:
- 编写一个Servlet对象的类意味着要编写一个特殊的类,这个特殊类是javax.servlet.http.HttpServlet的子类。
- HttpServlet类实现了Servlet接口,包罗了相应用户哀求的方法。
- HttpServlet的子类被称为一个Servlet类。
起首,你必要导入须要的包:
- import javax.servlet.*;
- import java.io.*;
复制代码 然后,你可以创建一个继承自HttpServlet的类,好比MyServlet
- public class MyServlet extends HttpServlet {
- ...
- }
复制代码 接下来,你大概想要覆盖doGet或doPost方法,由于它们分别对应HTTP的GET和POST哀求
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 这里处理GET请求
- }
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 这里处理POST请求
- }
复制代码 在这些方法中,你可以读取哀求数据,处置处罚业务逻辑,然后天生相应。比方,你可以如许处置处罚GET哀求:
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 设置响应内容类型为文本/html
- response.setContentType("text/html");
- // 获取输出流
- PrintWriter out = response.getWriter();
- // 输出响应内容
- out.println("<html>");
- out.println("<body>");
- out.println("<h1>Hello, Servlet</h1>");
- out.println("</body>");
- out.println("</html>");
- }
复制代码 留意,HttpServletRequest和HttpServletResponse都是Servlet接口的实现类,它们提供了处置处罚HTTP哀求和相应的方法。
为了让服务器知道你的Servlet,你必要在web.xml文件中设置它
- <servlet>
- <servlet-name>myServlet</servlet-name>
- <servlet-class>com.example.MyServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>myServlet</servlet-name>
- <url-pattern>/myservlet</url-pattern>
- </servlet-mapping>
复制代码 这段设置表现,当你访问http://yourserver.com/myservlet时,服务器会调用MyServlet。
总结一下,Servlet步伐实现的根本步调如下:
- 创建一个继承自HttpServlet的类。
- 覆盖doGet或doPost方法,处置处罚HTTP哀求。
- 在web.xml中设置Servlet,指定其名称和映射路径。
Servlet对象的工作原理及其生命周期、service()方法
工作原理:
- Servlet对象由Tomcat服务器负责管理,Tomcat服务器通过读取web.xml来创建并运行Servlet对象。
- Servlet对象有三个紧张的生命周期方法:init(), service() 和 destroy()。
生命周期:
- 初始化:当一个Servlet被实例化之后,容器将调用init()方法初始化这个对象,初始化是为了让Servlet对象在处置处罚客户端哀求前完成一些初始化的工作,比方创建数据库毗连、读取资源文件信息等。如果初始化失败,则此Servlet将被直接卸载。
- 处置处罚服务:当有哀求提交时,Servlet将调用service()方法(doGet()或doPost())举行处置处罚,在service()方法中,Servlet可以通过ServletRequest吸收客户的哀求,也可以利用ServletResponse设置相应信息。
- 烧毁:当WEB容器关闭大概检测到一个Servlet要从容器中被删除时,会主动调用destroy()方法,以便让该实例开释掉所占用的资源。
- 卸载:当一个Servlet调用完destroy()方法后,此实例将等待被垃圾网络器所接纳,当要再次利用此Servlet的时间,会重新调用init()方法初始化
service()方法
- service()方法是一个公共的void方法,担当HttpServletRequest和HttpServletResponse作为参数,抛出IOException和ServletException非常。
- 当Servlet对象创建和初始化后,该对象就调用service()方法来处置处罚用户的哀求并返反相应。
- 差别的客户哀求该Servlet对象时,服务器将启动一个新的线程,在该新线程中调用service()方法相应客户的需求。即每个客户的每次哀求都导致service()方法被实行,调用过程在差别的线程中,互不干扰。
起首,你必要导入须要的包
- import javax.servlet.*;
- import javax.servlet.http.*;
- import java.io.*;
复制代码 然后,你可以创建一个继承自HttpServlet的类,好比MyServlet
- public class MyServlet extends HttpServlet {
- ...
- }
复制代码 为了实现Servlet的生命周期方法,你必要重载init(), service() 和 destroy() 方法:
- @Override
- public void init(ServletConfig config) throws ServletException {
- System.out.println("Servlet初始化");
- }
- @Override
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- System.out.println("服务客户请求");
- }
- @Override
- public void destroy() {
- System.out.println("Servlet销毁");
- }
复制代码 留意,init()方法用于完成一些初始化工作,如加载资源、设置属性等;service()方法用于处置处罚客户端哀求;destroy()方法用于开释资源。
为了让服务器知道你的Servlet,你必要在web.xml中设置它
- <servlet>
- <servlet-name>myServlet</servlet-name>
- <servlet-class>com.example.MyServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>myServlet</servlet-name>
- <url-pattern>/myservlet</url-pattern>
- </servlet-mapping>
复制代码 这段设置表现,当你访问http://yourserver.com/myservlet时,服务器会调用MyServlet。
总结一下
Servlet对象的工作原理及生命周期如下:
- 当服务器启动时,会根据web.xml中的设置信息创建Servlet实例,并调用init()方法举行初始化。
- 当客户端发送哀求时,服务器会调用service()方法处置处罚哀求。
- 当服务器关闭时,会调用destroy()方法开释资源
service()方法的紧张作用如下:
- 当服务器吸收到客户端的哀求时,会启动一个新的线程来实行service()方法。
- service()方法可以根据哀求范例调用doGet()或doPost()等方法来处置处罚特定范例的哀求。
- 每个客户的每次哀求都会导致service()方法被单独实行,因此不会互干系扰。
Servlet对象的共享变量
Servlet类是HttpServlet的一个子类,在编写子类时可以声明一些成员变量。当用户哀求加载Servlet时,服务器分别为每个用户启动一个线程,在该线程中Servlet调用service()方法相应客户的需求,而Servlet类的成员变量是被全部线程共享的数据。
- import javax.servlet.*;
- import javax.servlet.http.*;
- import java.io.*;public class MyServlet extends HttpServlet { private int count = 0; ...}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { synchronized (this) { count++; System.out.println("当前访问次数:" + count); }}
复制代码 我们声明白一个名为count的成员变量,它的初始值为0
每当有一个新的哀求到来时,count就会加1,并打印出来
通过JSP页面访问servlet
可以通过JSP页面来哀求一个Servlet。也就是说,可以让JSP页面负责数据的表现,而让一个Servlet去做和处置处罚数据有关的事变。
Web服务目次下的JSP页面都可以通过表单或超链接哀求该Web服务目次下的某个Servlet。
eg. 创建一个JSP页面,好比index.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>访问Servlet示例</title>
- </head>
- <body>
- <form action="MyServlet" method="post">
- 用户名:<input type="text" name="username"><br>
- 密码:<input type="password" name="password"><br>
- <input type="submit" value="登录">
- </form>
- </body>
- </html>
复制代码 在这个例子中,我们创建了一个简单的表单,用户输入用户名和暗码后点击“登录”按钮,表单将会提交到MyServlet。
创建一个Servlet,好比MyServlet.java
- import javax.servlet.*;
- import javax.servlet.http.*;
- import java.io.*;public class MyServlet extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); if ("admin".equals(username) && "123456".equals(password)) { response.sendRedirect("/success.jsp"); } else { response.sendRedirect("/error.jsp"); } }}
复制代码 在这个例子中,我们查抄用户名和暗码是否精确,如果精确则跳转到/success.jsp,否则跳转到/error.jsp。
通过JSP页面访问Servlet的紧张步调如下:
- 创建一个JSP页面,包罗一个表单大概超链接。
- 表单或超链接指向一个Servlet。
- 编写Servlet处置处罚哀求。
- 设置web.xml。
doGet()方法和doPost()方法
这两个方法都是Servlet类中的方法,它们是处置处罚HTTP哀求的紧张入口点。在Servlet生命周期中,每当有新的HTTP哀求到达Servlet容器时,Servlet引擎就会调用相应的doGet()大概doPost()方法来处置处罚这个哀求。
doGet()方法用来处置处罚HTTP的GET哀求,而doPost()方法则用来处置处罚HTTP的POST哀求。这两种哀求方式的紧张区别在于,GET哀求的数据会被附加到URL背面,以问号的情势出现;而POST哀求的数据则是放在HTTP包体中的。
- import java.io.*;
- import javax.servlet.*;
- import javax.servlet.http.*;
- public class MyServlet extends HttpServlet {
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 设置响应内容类型
- response.setContentType("text/html");
- // 获取输出流
- PrintWriter out = response.getWriter();
- // 输出欢迎信息
- out.println("<html>");
- out.println("<body>");
- out.println("<h1>Welcome to Servlet</h1>");
- out.println("</body>");
- out.println("</html>");
- }
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- // 这里可以处理POST请求特有的逻辑,比如上传文件等
- // 然后我们可以调用doGet()方法来处理剩下的逻辑
- this.doGet(request, response);
- }
- }
复制代码 我们创建了一个名为MyServlet的Servlet类,并重写了doGet()和doPost()方法。在doGet()方法中,我们简单地返回了一段HTML文本作为相应。而在doPost()方法中,固然没有详细的实现,但你可以在这里添加处置处罚POST哀求的特定逻辑,比方处置处罚文件上传等。末了,我们调用了this.doGet(request, response),如许就可以共享doGet()方法中的逻辑了。
Servlet跳转
从一个JSP大概是一个HTML页面可以通过表单或超链接跳转进Servlet,那么从Servlet也可以跳转到其他的Servlet、JSP或其他页面。
跳转的两种情势
1.客户端跳转(重定向):地点栏会跳转
客户端跳转,也称为重定向,是一种常见的Web应用步伐中的跳转方式。它答应用户从一个Servlet大概JSP页面跳转到另一个Servlet大概JSP页面。这种跳转方式的特点是欣赏器会发起一个新的HTTP哀求,因此在新页面中无法访问原哀求中的数据
在Servlet中,我们通常利用HttpServletResponse接口的sendRedirect()方法来举行客户端跳转。
- import javax.servlet.http.*;
- public class RedirectServlet extends HttpServlet {
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // 设置响应头为重定向
- response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
- response.setHeader("Location", "http://www.example.com/newPage.jsp");
- // 结束响应
- response.flushBuffer();
- }
- }
复制代码 当用户访问RedirectServlet时,Servlet将会把用户重定向到http://www.example.com/newPage.jsp这个页面。必要留意的是,由于这是客户端跳转,以是新的页面无法直接访问原来哀求中的数据。
别的,客户端跳转只能转达session范围内的属性,而不能转达request范围的属性。这是由于,在重定向过程中,欣赏器会发起一个新的HTTP哀求,原来的request对象已经失效了。如果必要在多个页面之间共享数据,发起利用session对象存储数据。
2.服务器端跳转(哀求转发):地点栏不会跳转
服务器端跳转,也被称为哀求转发,是一种在Java Web开发中用于在差别Servlet或JSP页面之间举行跳转的方法。
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- @WebServlet("/FirstServlet")
- public class FirstServlet extends HttpServlet {
- protected void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 获取RequestDispatcher对象
- RequestDispatcher rd = request.getRequestDispatcher("SecondServlet");
- // 转发请求
- rd.forward(request, response);
- }
- }
- import java.io.IOException;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- @WebServlet("/SecondServlet")
- public class SecondServlet extends HttpServlet {
- protected void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 访问来自第一个Servlet的数据
- String dataFromFirstServlet = (String) request.getParameter("data");
- // 处理数据...
- }
- }
复制代码 FirstServlet起首获取了一个RequestDispatcher对象,然后调用其forward()方法将哀求转发给了SecondServlet。SecondServlet可以在吸收到的哀求中访问FirstServlet传来的数据。
服务器端跳转的长处在于它可以方便地在差别的Servlet或JSP页面之间共享数据,这对于必要跨页面处置处罚数据的应用步伐非常有用。然而,它的缺点是它要叱责部的Servlet和JSP页面都在同一个Web应用中,而且必须位于同一台服务器上。
利用session
HTTP协议自己是一种无状态协议,也就是说服务器并不知道哪个哀求来自于哪个用户。为了跟踪用户的状态信息,我们必要一种机制来纪录每个用户的特定信息。这就是Session的作用。
Session是一种技能,用来生存用户的信息,比方登录状态、购物车等。每个用户都有自己的Session,它们之间互不干扰。Servlet类利用session对象来纪录有关毗连的信息。
获取用户会话的方法是通过HttpServletRequest的对象request调用getSession()方法来获取用户的会话对象。
一个用户在差别的servlet对象中获取的session对象是完全类似的,差别的用户的session对象互不类似。
- import javax.servlet.*;
- import javax.servlet.http.*;
- public class SessionServlet extends HttpServlet {
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 获取session对象
- HttpSession session = request.getSession(true);
- // 如果session不存在,则创建一个新的session
- if(session == null){
- session = request.getSession();
- }
- // 设置session的属性
- session.setAttribute("username", "John Doe");
- // 获取session的属性
- String username = (String) session.getAttribute("username");
- }
- }
复制代码 getSession(true)方法会实行获取当前用户的session。如果没有找到对应的session,就会主动创建一个新的session。然后我们可以利用setAttribute()方法来设置session的属性,以及getAttribute()方法来获取session的属性。
必要留意的是,一个用户在差别的servlet对象中获取的session对象是完全类似的,差别的用户的session对象互不类似。这意味着,你可以在一个servlet中设置session的属性,然后在另一个servlet中读取这些属性。
Servlet转达参数到JSP ---利用session
在Servlet中,你可以利用HttpSession对象来转达参数到JSP页面。
- import javax.servlet.*;
- import javax.servlet.http.*;
- public class ServletExample extends HttpServlet {
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 获取session对象
- HttpSession session = request.getSession();
- // 设置session的属性
- session.setAttribute("name", "John Doe");
- // 使用客户端跳转
- response.sendRedirect("jsp/example.jsp");
- }
- }
复制代码 起首获取了session对象,然后设置了名为"name"的属性,并将其值设为"John Doe"。然后我们利用sendRedirect()方法举行了客户端跳转
在JSP页面中,我们可以利用EL表达式大概JSTL标签库来获取这个属性
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <html>
- <body>
- <h1>Hello ${sessionScope.name}!</h1> <!-- 使用EL表达式 -->
- </body>
- </html>
- 或者
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <html>
- <body>
- <h1>Hello <c:out value="${sessionScope.name}" />!</h1> <!-- 使用JSTL标签库 -->
- </body>
- </html>
- 当然,你也可以使用getAttribute()方法来获取这个属性
- <%
- String name = (String) session.getAttribute("name");
- %>
- <html>
- <body>
- <h1>Hello <%=name %>!</h1> <!-- 使用脚本元素 -->
- </body>
- </html>
复制代码 必要留意的是,这种方法实用于客户端跳转和服务器端跳转。无论你是利用sendRedirect()还是forward()方法,只要用户还在同一个session内,就可以访问到这个属性。
Servlet转达参数到JSP ---利用request
在Servlet中,除了利用session之外,还可以利用request对象来转达参数到JSP页面。这是一种更有服从的方法,由于它不必要创建新的session,只必要将哀求转发给目标页面即可。
- import javax.servlet.*;
- import javax.servlet.http.*;
- public class ServletExample extends HttpServlet {
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- // 设置request的属性
- request.setAttribute("name", "John Doe");
- // 使用服务器端跳转
- RequestDispatcher dispatcher = request.getRequestDispatcher("A.jsp");
- dispatcher.forward(request, response);
- }
- }
复制代码 起首设置了名为"name"的属性,并将其值设为"John Doe"。然后我们利用forward()方法举行了服务器端跳转。
在JSP页面中,我们可以利用EL表达式大概JSTL标签库来获取这个属性
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <html>
- <body>
- <h1>Hello ${name}!</h1> <!-- 使用EL表达式 -->
- </body>
- </html>
- 或者
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <html>
- <body>
- <h1>Hello <c:out value="${name}" />!</h1> <!-- 使用JSTL标签库 -->
- </body>
- </html>
- 或者
- <%
- String name = (String) request.getAttribute("name");
- %>
- <html>
- <body>
- <h1>Hello <%=name %>!</h1> <!-- 使用脚本元素 -->
- </body>
- </html>
复制代码 留意,这种方法只实用于服务器端跳转。由于只有服务器端跳转才气保持原始的request对象,客户端跳转会创建一个新的request对象,以是无法访问到之前设置的属性。
JSP与数据库访问
JSP(JavaServer Pages)是一种动态网页技能,可以用来天生HTML、XML或其他范例的文档。在JSP中,可以通过JDBC(Java Database Connectivity)来访问数据库
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.SQLException;
- public class MySQLConnection {
- public static Connection getConnection() throws SQLException {
- return DriverManager.getConnection(
- "jdbc:mysql://localhost:3306/mydatabase",
- "username",
- "password"
- );
- }
- }
复制代码 增删查改”数据库纪录:
- 增长纪录:利用PreparedStatement的executeUpdate()方法实行INSERT语句。
- 删除纪录:利用PreparedStatement的executeUpdate()方法实行DELETE语句。
- 查询纪录:利用Statement或PreparedStatement的executeQuery()方法实行SELECT语句。
- 修改纪录:利用PreparedStatement的executeUpdate()方法实行UPDATE语句。
一个简单的例子,展示了怎样利用JDBC从MySQL数据库中查询数据
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- public class JDBCDemo {
- public static void main(String[] args) {
- try {
- Connection conn = MySQLConnection.getConnection();
- String sql = "SELECT * FROM users WHERE id = ?";
- PreparedStatement pstmt = conn.prepareStatement(sql);
- pstmt.setInt(1, 1); // 设置占位符的值
- ResultSet rs = pstmt.executeQuery(); // 执行SQL语句
- while(rs.next()) { // 遍历结果集
- System.out.println(rs.getString("name"));
- }
- rs.close();
- pstmt.close();
- conn.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
复制代码 先创建了到数据库的毗连,然后预备了一个带占位符的SQL语句,设置了占位符的值,实行了SQL语句,遍历了效果集,末了关闭了效果集、预编译的语句和毗连。
JDBC
JDBC概述
JDBC是Java环境中访问数据库的一组API,它由一些Java语言编写的类和接口构成,能方便地向任何关系型数据库发送SQL下令。
JDBC为数据库应用开发职员开发职员提供了一种尺度的应用步伐筹划接口,使开发职员可以用纯Java语言编写完备的数据库应用步伐。
操纵差别的数据库仅仅是毗连方式上的差别而已。
利用JDBC的应用步伐一旦与数据库创建毗连,就可以利用JDBC提供的API操纵数据库。
JDBC数据库举行交互
在JDBC中,要与数据库举行交互,起首要加载并注册相应的数据库驱动。这是通过Driver接口完成的。Driver接口界说了一些方法,如connect(),用于创建与数据库的毗连。详细步调如下:
- 加载驱动:利用Class.forName()方法加载数据库驱动。这个方法会查找并初始化指定类,如果该类实现了Driver接口,那么就会调用其register()方法,将实在例注册到DriverManager中。
- try {
- Class.forName("com.mysql.jdbc.Driver");
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
复制代码 - 创建毗连:利用DriverManager.getConnection()方法创建与数据库的毗连。
- try {
- Connection con = DriverManager.getConnection(url, user, password);
- } catch (SQLException e) {
- e.printStackTrace();
- }
复制代码 此中,url是数据库的URL,user和password是数据库的用户名和暗码。
完备代码
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.SQLException;
- public class JDBCExample {
- public static void main(String[] args) {
- try {
- // 加载并注册驱动
- Class.forName("com.mysql.jdbc.Driver");
- // 创建与数据库的连接
- Connection con = DriverManager.getConnection(
- "jdbc:mysql://localhost:3306/mydatabase",
- "username",
- "password"
- );
- // 使用连接...
- con.close(); // 关闭连接
- } catch (ClassNotFoundException | SQLException e) {
- e.printStackTrace();
- }
- }
- }
复制代码 大多数JDBC驱动步伐都把初始化工作放在Driver接口实现类的静态初始化模块中,因此在利用驱动步伐前一样平常要用Class.forName()显式加载驱动步伐。但有些驱动步伐(如Oracle的JDBC驱动)则不必要如许做,可以直接利用DriverManager.getConnection()方法。
DriverManager类
DriverManager类是JDBC的焦点类之一,紧张负责管理数据库毗连。它的紧张功能包罗:
- 注册驱动:当一个Driver接口的实现类被加载时,DriverManager会主动调用其register()方法,将实在例注册到DriverManager中。
- 创建毗连:DriverManager维护着一个已注册的Driver列表,当必要创建数据库毗连时,它会遍历这个列表,找到符合的Driver来创建毗连。
getConnection()方法是DriverManager的紧张方法,用于获取数据库毗连。它的常用重载版本有三个:
getConnection(String url):返回与给定URL的数据库的毗连。
getConnection(String url, String user, String password):返回与给定URL的数据库的毗连,并利用给定的用户名和暗码。
getConnection(String url, Properties info):返回与给定URL的数据库的毗连,并利用给定的属性。
利用getConnection()方法获取与MySQL数据库的毗连
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.SQLException;
- public class JDBCExample {
- public static void main(String[] args) {
- try {
- // 加载并注册驱动
- Class.forName("com.mysql.jdbc.Driver");
- // 创建与数据库的连接
- Connection con = DriverManager.getConnection(
- "jdbc:mysql://localhost:3306/mydatabase",
- "username",
- "password"
- );
- // 使用连接...
- con.close(); // 关闭连接
- } catch (ClassNotFoundException | SQLException e) {
- e.printStackTrace();
- }
- }
- }
复制代码 getConnection()方法的第一个参数是数据库的URL,第二个和第三个参数分别是数据库的用户名和暗码。
创建Statement对象
发送SQL语句紧张是通过Statement对象完成的。Statement对象由Connection对象创建,代表一个数据库会话。Statement对象紧张用于实行静态SQL语句,并能返回实行效果。
Statement接口中有很多方法,常用的有:
executeQuery(String sql):实行SQL查询语句,并返回一个ResultSet对象。
executeUpdate(String sql):实行SQL更新语句(插入、删除、修改),并返回受影响的行数。
close():关闭Statement对象。
比方,以下代码创建了一个Statement对象,并实行了一个查询语句
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.Statement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- public class JDBCExample {
- public static void main(String[] args) {
- try {
- // 加载并注册驱动
- Class.forName("com.mysql.jdbc.Driver");
- // 创建与数据库的连接
- Connection con = DriverManager.getConnection(
- "jdbc:mysql://localhost:3306/mydatabase",
- "username",
- "password"
- );
- // 创建Statement对象
- Statement stmt = con.createStatement();
- // 执行查询语句
- ResultSet rs = stmt.executeQuery("SELECT * FROM mytable");
- // 处理结果集...
- rs.close();
- stmt.close();
- con.close();
- } catch (ClassNotFoundException | SQLException e) {
- e.printStackTrace();
- }
- }
- }
复制代码 在这个例子中,createStatement()方法创建了一个Statement对象,executeQuery()方法实行了一个查询语句,并返回了一个ResultSet对象,表现查询的效果。
Statement接口常用方法
Statement是Java数据库毗连(JDBC)API中的一个接口,用于实行SQL语句,并返回效果。
- ResultSet executeQuery(String sql) throws SQLException: 这个方法用于实行查询语句(SELECT),并将效果放在ResultSet对象中。ResultSet是一个游标模子,可以逐行访问效果集。
- String sql = "SELECT * FROM employees";
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(sql);
- while (rs.next()) {
- System.out.println(rs.getString("name") + ", " + rs.getInt("age"));
- }
复制代码 - int executeUpdate(String sql) throws SQLException: 这个方法用于实行修改或插入语句(INSERT, UPDATE, DELETE),并返回受影响的纪录数。
- String sql = "DELETE FROM employees WHERE age > 60";
- int rowsAffected = stmt.executeUpdate(sql);
- System.out.println(rowsAffected + " records deleted");
复制代码 - boolean execute(String sql) throws SQLException: 这个方法用于实行任何范例的SQL语句,包罗查询和更新。如果实行乐成,返回true;否则返回false。
- String sql = "CREATE TABLE employees (id INT PRIMARY KEY, name VARCHAR(50), age INT)";
- boolean success = stmt.execute(sql);
- if (success) {
- System.out.println("Table created successfully");
- } else {
- System.out.println("Failed to create table");
- }
复制代码 以上全部操纵都必要一个有用的Connection对象conn。在实际应用中,你必要先通过DriverManager.getConnection()方法获取到数据库毗连。
ResultSet接口
ResultSet是Java数据库毗连(JDBC)API中的一个接口,表现从数据库查询得到的效果集。当实行了一个查询语句后,Statement或PreparedStatement对象会返回一个ResultSet对象,该对象包罗了满足查询条件的全部行。
- ResultSet类界说了访问实行Statement产生的效果集的方法:
- next(): 移动光标到下一行。
- getXXX(int columnIndex): 根据列号获取值。
- getXXX(String columnName): 根据列名获取值
- // 假设我们有一个名为employees的表,包含id, name, age三列
- String sql = "SELECT * FROM employees";
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(sql);
- // 遍历结果集
- while (rs.next()) {
- // 获取第1列(记住,列是从1开始计数的)
- int id = rs.getInt(1);
- // 或者,你可以使用列名来获取值
- String name = rs.getString("name");
- int age = rs.getInt("age");
- System.out.println(id + ": " + name + ", " + age);
- }
- // 注意:一定要关闭资源
- rs.close();
- stmt.close();
复制代码
- 效果集一样平常是一个表,此中有查询返回的列标题及相应的值:
- 列标题可以通过getMetaData()方法得到,它返回一个ResultSetMetaData对象,此中包罗了列的数量和名称。
- ResultSetMetaData meta = rs.getMetaData();
- for (int i = 1; i <= meta.getColumnCount(); i++) {
- System.out.print(meta.getColumnName(i) + "\t");
- }
- System.out.println();
- while (rs.next()) {
- for (int i = 1; i <= meta.getColumnCount(); i++) {
- System.out.print(rs.getObject(i) + "\t");
- }
- System.out.println();
- }
复制代码
查询操纵
与数据库创建毗连后,就可以利用JDBC提供的API和数据库交互信息,好比查询、修改和更新数据库中的表等。
- import java.sql.*;
- public class JdbcExample {
- public static void main(String[] args) {
- try {
- // 加载驱动
- Class.forName("com.mysql.jdbc.Driver");
-
- // 创建数据库连接
- Connection conn = DriverManager.getConnection(
- "jdbc:mysql://localhost:3306/mydatabase",
- "username",
- "password"
- );
-
- // 创建Statement对象
- Statement stmt = conn.createStatement();
-
- // 执行查询语句
- ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
-
- // 处理查询结果
- while (rs.next()) {
- int id = rs.getInt("id");
- String name = rs.getString("name");
- int age = rs.getInt("age");
-
- System.out.println(id + ": " + name + ", " + age);
- }
-
- // 关闭资源
- rs.close();
- stmt.close();
- conn.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
复制代码 起首加载MySQL的JDBC驱动,然后创建一个数据库毗连。接着,我们创建一个Statement对象,并利用它来实行一个查询语句。末了,我们遍历查询效果,并打印出每一行的数据。
JDBC与数据库表举行交互的紧张方式是利用SQL语句,JDBC提供的API可以将尺度的SQL语句发送给数据库,实现与数据库的交互
- try {
- PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM employees WHERE name = ?");
- pstmt.setString(1, "John Doe"); // 设置第一个参数为"John Doe"
-
- ResultSet rs = pstmt.executeQuery();
-
- while (rs.next()) {
- int id = rs.getInt("id");
- String name = rs.getString("name");
- int age = rs.getInt("age");
-
- System.out.println(id + ": " + name + ", " + age);
- }
-
- rs.close();
- pstmt.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
复制代码 利用PreparedStatement来实行一个带有参数的查询语句。我们起首预备一个SQL语句,然后设置参数,末了实行查询。如许做的长处是可以克制SQL注入攻击,由于全部的输入都会被精确地转义。
处置处罚查询效果的方法
ResultSet对象一次只能看到一个数据行,利用next()方法使光标走到下一行,得到一行数据后,只要将位置索引或字段名转达给getXxx方法就可得到字段值。
- ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
- while (rs.next()) { // 每次调用next()方法,光标就会移动到下一行
- int id = rs.getInt(1); // 使用位置索引来获取第一列的值
- String name = rs.getString("name"); // 使用字段名来获取第二列的值
- System.out.println(id + ": " + name);
- }
复制代码 起首实行一个查询语句,然后遍历效果集。每次调用next()方法,光标就会移动到下一行。我们利用位置索引(从1开始)或字段名来获取每行的值。
无论字段是何种属性,都可以利用getString(col)方法返回字段值的字符串表现
- ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
- while (rs.next()) {
- String idStr = rs.getString(1); // 将整型字段转换为字符串
- String name = rs.getString("name"); // 直接获取字符串字段
-
- System.out.println(idStr + ": " + name);
- }
复制代码 利用getString()方法来获取每个字段的字符串表现。纵然字段是整型或其他范例,这个方法也能正常工作。
当利用getXxx方法检察一行纪录时,不可以颠倒字段的序次。
- ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
- while (rs.next()) {
- String name = rs.getString("name"); // 先获取name字段
- int id = rs.getInt(1); // 再获取id字段
-
- System.out.println(id + ": " + name);
- }
复制代码 在这个例子中,我们不能先获取id字段,然后再获取name字段,由于一旦调用了getString()方法,光标就已经移动到了下一行。以是,我们必须按照精确的序次来获取字段。
含糊查询
条件查询:通过在SQL语句中WHERE子句中指定查询条件来实现条件查询
- String sql = "SELECT * FROM employees WHERE salary > 5000"; // 查询工资大于5000的员工
- ResultSet rs = stmt.executeQuery(sql);
- while (rs.next()) {
- int id = rs.getInt(1);
- String name = rs.getString("name");
- double salary = rs.getDouble("salary");
-
- System.out.println(id + ": " + name + ", " + salary);
- }
复制代码 利用WHERE子句来限定查询效果。只有满足条件的行才会出如今效果会合。
含糊查询:通过用SQL语句操纵符LIKE举行模式匹配,利用%代替0个或多个字符,用下划线_代替一个字符,来实现含糊查询。
- String sql = "SELECT * FROM employees WHERE name LIKE '张%'; // 查询名字以'张'开头的员工
- ResultSet rs = stmt.executeQuery(sql);
- while (rs.next()) {
- int id = rs.getInt(1);
- String name = rs.getString("name");
-
- System.out.println(id + ": " + name);
- }
复制代码 利用LIKE操纵符来举行含糊查询。%代表恣意数量的字符,以是我们找到了全部名字以'张'开头的员工。
- String sql = "SELECT * FROM employees WHERE name LIKE '_明%'; // 查询名字第二个字是'明'的员工
- ResultSet rs = stmt.executeQuery(sql);
- while (rs.next()) {
- int id = rs.getInt(1);
- String name = rs.getString("name");
-
- System.out.println(id + ": " + name);
- }
复制代码 利用_来代替一个字符,以是我们找到了全部名字第二个字是'明'的员工。
更新、添加与删除操纵
通过Statement对象调用executeUpdate(SQL语句)实行更新、添加和删除纪录的SQL语句来实现更新、添加和删除等操纵。
- // 更新一条记录
- String sql = "UPDATE employees SET salary = 8000 WHERE name='张三'";
- int rowsAffected = stmt.executeUpdate(sql); // 返回受影响的行数
- // 添加一条记录
- sql = "INSERT INTO employees(name, salary) VALUES('李四', 7000)";
- rowsAffected = stmt.executeUpdate(sql);
- // 删除一条记录
- sql = "DELETE FROM employees WHERE name='王五'";
- rowsAffected = stmt.executeUpdate(sql);
复制代码 利用Statement对象的executeUpdate()方法来实行更新、添加和删除操纵。这个方法会返回受影响的行数,如果乐成则返回1,否则返回0
更新、添加和删除纪录的SQL语法:
- UPDATE <表名> SET <字段名>=新值 WHERE <条件子句>
- INSERT INTO 表(字段列表) VALUES (对应的详细纪录)
- DELETE FROM <表名> WHERE <条件子句>
- UPDATE employees SET salary = 8000 WHERE name='张三';
- INSERT INTO employees(name, salary) VALUES('李四', 7000);
- DELETE FROM employees WHERE name='王五';
复制代码 这些是根本的SQL语句,用于更新、添加和删除纪录。留意,添加纪录时,如果没有指定字段列表,则必要提供完备的纪录,包罗全部字段的值。
事件
事件由一组SQL语句构成,所谓“事件处置处罚”是指:应用步伐包管事件中的SQL语句要么全部都实行,要么一个都不实行。
- Connection con = ...; // 假设已经获得了数据库连接
- con.setAutoCommit(false); // 关闭自动提交
- try {
- con.createStatement().executeUpdate("UPDATE employees SET salary = 8000 WHERE name='张三'");
- con.createStatement().executeUpdate("INSERT INTO employees(name, salary) VALUES('李四', 7000)");
- con.commit(); // 提交事务
- } catch (SQLException e) {
- con.rollback(); // 回滚事务
- }
复制代码 关闭了主动提交,然后实行了一组SQL语句。如果此中任何一个语句失败,那么整个事件都会回滚,即规复到事件开始之前的状态。如果全部语句都乐成,我们就提交事件,让它们见效。
事件是包管数据库中数据完备性与同等性的机制。JDBC事件处置处罚步调如下:
- setAutoCommit(boolean autoCommit)方法:为了能举行事件处置处罚,必须关闭毗连对象 con 的默认设置。
- commit()方法:毗连对象 con 调用commit()方法就是让事件中的SQL语句全部见效。
- rollback()方法:毗连对象 con 调用rollback()方法,打消引起数据发生厘革的SQL语句操纵,将数据库中的数据规复到commit()方法实行之前的状态。
- con.setAutoCommit(false); // 关闭自动提交
- try {
- con.createStatement().executeUpdate("UPDATE employees SET salary = 8000 WHERE name='张三'");
- con.createStatement().executeUpdate("INSERT INTO employees(name, salary) VALUES('李四', 7000)");
- con.commit(); // 提交事务
- } catch (SQLException e) {
- con.rollback(); // 回滚事务
- }
复制代码
|