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}

数据级联:

image-20210131201311743

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中的配置

image-20210202135551392

实际开发中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

image-20210204130554852

不能用表单提交请求,改用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原理

image-20210204132551471

基于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,供厂商开发数据库的驱动程序

image-20210205104755355

image-20210205105203744

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

image-20210205141348931

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&amp;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中响应给用户。

项目资源链接:

https://pan.baidu.com/s/1MDbbNKqC5mgUGg2yUiM9cg 提取码:zmpi

猜你喜欢

转载自blog.csdn.net/weixin_51418572/article/details/114276988