JavaWeb入门学习

作者Gitee地址 https://gitee.com/thciweicloud
作者项目 面包博客,一个微服务架构的前后端分离博客系统。

Tomcat

概述

Tomcat是安装在本地的一个服务

安装

Apache Tomcat® - Apache Tomcat 9 Software Downloads

文件

bin:存放各个平台下启动和停止Tomcat 服务的脚本文件

conf:存放各种Tomcat 服务器的配置文件

lib:存放Tomcat 服务器所需要的 jar包

logs:存放Tomcat 服务运行的日志

temp:Tomcat 运行时的临时文件

webapps:存放允许客户端访问的资源(java程序)

work:存放Tomcat 将JSP 转换后之后的Servlet文件

部署

如:在下面地址打开http://localhost:8009/javademo_war_exploded/

​ // IP / 端口 / application name

如果在新建项目的界面有application server当然最好了,直接选择Tomcat

如果没有,只能选择以下操作了

配置Tomcat

因为我的8080端口被占用,所以要更改端口,8009可以一试

netstat -an 可以查看所有端口

还有一种方式,找到占用者然后干掉它

netstat -ano|findstr 8080
taskkill -pid 占用端口名称 –f

关于1099的经典报错如何处理

netstat -ano|findstr 1099
taskkill -pid 占用端口名称 –f

1099作为idea神坑之一

有的时候用查找进程的方式往往会找不到进程,无法解决问题,那么我们可以在Tomcat配置中把1099改成1098即可

为了测试时简化url,所以我们最好改成如 http://localhost:8009/ 此类,这时记得在 run-》Edit configurations -》deployment 将工程的 Application context 改为 /

配置问题

  • 如果IDEA中没有Servlet时,File/projects structure/Modules/手动添加jar包或者直接添加Tomcat

  • JSP中不能使用out对象,File–》project structure–》Libraries , 添加 tomcat 的 jar包 或者直接添加 lib

  • 调试时按钮变灰且显示

Connected to the target VM, address: ‘127.0.0.1:4597’, transport: ‘socket’

此时在 pom.xml 加入

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • io流上传 遭遇乱码文件

1、File->Settings->Editor->File Encodings

2、File->Other Settings->Default Settings ->Editor->File Encodings

3、将项目中的.idea文件夹中的encodings.xml文件中的编码格式改为uft-8

4、File->Settings->Build,Execution,Deployment -> Compiler -> Java Compiler。设置 Additional command line parameters选项为 -encoding utf-8

5、打开Run/Debug Edit Configurations,选择你的tomcat。然后在 Server > VM options 设置为 -Dfile.encoding=UTF-8 ,重启tomcat

  • 编码问题详述

解决日志不乱码且output不乱码,一个GBK,全局UTF-8

https://blog.csdn.net/qq_43598138/article/details/109311992?ops_request_misc=&request_id=&biz_id=102&utm_term=tomcat%25E8%25AD%25A6%25E5%2591%258A%25E4%25B9%25B1%25E7%25A0%2581&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-109311992.first_rank_v2_pc_rank_v29


Servlet

javademo2

理解

  • 什么是 Servlet?

Servlet是 Java Web开发的基石,与平台无关的服务器组件,它是运行在 Servlet容器/Web应用服务器/ Tomcat,负责与客户端进行通信
Servlet的功能:

1.创建并返回基于客户请求的动态HTML页面

2.与数据库进行通信

  • 如何使用Serlvet?

Servlet本身是一组接口,自定义一个类,并且实现 Servlet 接口,这个类就具备了接受客户端请求以及做出响应的功能

1.1 配置

Servlet并不能直接像index.jsp一样直接访问,如果路径使用out/WEB-INF/classes/servlet,仍然不可以(浏览器无权限),所以我们要通过物理映射来间接访问Servlet

  • out/web.xml
<servlet>
        <servlet-name>MyServlet</servlet-name>
  <servlet-class>com.thciwei.servlet.myServlet</servlet-class>
</servlet>
<servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/myservlet</url-pattern>
</servlet-mapping>
  • 基于注解的方式

在.java文件下的类前

@WebServlet("/myservlet")

1.2 实现一个简单的通信

http://localhost:8009/test/myservlet?id=1

   @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("客户端你好,我已经接收你的请求");
    }

我是Servlet,我已经接受到客户端的请求,参数是1

1.3 Servlet的生命周期

1、当浏览器访问 Servlet 的时候,Tomcat会查询当前 Servlet 的实例化对象是否存在,如果不存在,则通过反射机制动态创建对象,如果存在,直接执行第3步

2、调用 init 方法完成初始化操作

3、调用service 方法完成业务逻辑操作

4、关闭Tomcat,调用destory方法,释放当前对象所占用的资源

1.4 Servlet 的层次结构

我们可以直接继承使用HttpServlet,看到这里,结束

Servlet —》 GenericServlet —》HttpServlet

HTTP 请求有很多种类型,常用的有四种

GET 读取

POST 保存

PUT 修改

DELETE 删除

GenericServlet 实现 Servlet 接口,同时为它的子类屏蔽了不常用的方法,子类只需要重写 service 方法即可

HttpServlet 继承 GenericServlet,根据请求类型进行分发处理,GET 进入doGet 方法, POST 进入 doPost 方法

开发者自定义的Servlet 类只需要继承 HttpServlet 即可,重写 doGet 和 doPost

我们来山寨一下HttpServlet(抽离核心和继承结构

MyGenericServlet

import javax.servlet.*;
import java.io.IOException;

public class MyGenericServlet 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 {
    
    

    }

    @Override
    public String getServletInfo() {
    
    
        return null;
    }

    @Override
    public void destroy() {
    
    

    }
}

MyHttpServlet

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
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("/mytest")
public class MyHttpServlet extends MyGenericServlet {
    
    
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    
    
       HttpServletRequest request=(HttpServletRequest) servletRequest;
        HttpServletResponse response=(HttpServletResponse) servletResponse;
        //需要转换类型。向下转型
        String method=request.getMethod();
     switch(method){
    
    
         case "GET":
             this.doGet(request,response);
         case "POST":
             this.doPost(request,response);
             break;
     }
    }
    public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException{
    
    

    }
    public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException{
    
    

    }
}

helloServlet

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/hello")
public class HelloServlet extends MyHttpServlet{
    
    
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
    
    
       response.getWriter().write("HelloGet");
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException{
    
    
       response.getWriter().write("HelloPost");
    }
}


JSP

JSP本质上就是一个Servlet,JSP 主要负责与用户交互, 将最终的界面呈现给用户,Html+JS+CSS+java的混合文件

理解

因为Servlet是唯一和服务端响应的(只有Servlet能处理客户端的请求),所以是把 JSP 转换成Servlet来呈现界面的,JSP的特性是什么呢?JSP中可以写java代码,那么我们就可以在html中穿插java,所以实际上JSP属于中间层的东西。底层原理即转换成Servlet,把html等和java混合之后的东西一行一行输出。

当服务器接收到一个后缀是jsp的请求时,将该请求交给JSP引擎处理,每一个 JSP页面 第一次被访问的时候, JSP引擎会将它翻译成一个 Servlet 文件,再由Web容器调用 Servlet完成响应。

单纯从开发角度,JSP 就是在 HTML 中嵌入 java程序

具体嵌入方式三种:

1、JSP 脚本,执行 java 逻辑代码

<% java代码 %>

2、JSP声明:定义 java 方法

<%! java方法 %>
<%  调用方法  %>

3、JSP 表达式:把 java 对象直接输出到 HTML 页面中

<%=java 变量 %>
比如  <%!
    public String test(){
      return "hello";
    }
  %>
   <%
    String str1=test();
   %>
  <%=str1%>

JSP内置对象9个

1、request:表示一次请求,HttpServletRequest

2、response:表示一次响应,HttpServletResponse

3、pageContext:获取页面信息,页面上下文,PageContext

4、session:表示一次对话,保存用户信息,HttpSession

5、application:表示当前Web应用,全局对象,保存所有用户共享信息,ServletContext

6、config:当前 JSP对应的Servlet 的ServletConfig 对象,获取Servlet的信息

7、out:向浏览器输出数据,JspWriter

8、page:当前 JSP对应的Servlet对象,Servlet

9、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).forward(request,response)

返回一个 RequestDispatcher对象,forward方法用于请求转发

5、String[] getparameterValues() 获取客户端多个同名参数

6、void setCharacterEncoding(String charset) 指定每个请求的编码

如 (UTF-8)

HTTP请求状态码

200:正常

404:资源找不到

400:请求类型不匹配

500:java抛出异常

302: 重定向

response 常用方法

sendRedirect(String path) 重定向、页面之间的跳转

转发 getRequestDispatcher 和重定向 sendRedirect 的区别 :

转发是将同一个请求传给下一个页面,重定向是创建一个新的请求传给下一个页面,之前的请求结束生命周期

转发:同一个请求在服务器之间传递,地址栏不变,也叫服务器跳转

重定向:由客户端发送一次新的请求来访问跳转后的目标资源,地址栏改变,也叫客户端跳转

如果两个页面之间需要通过 request 来传值,则必须使用req.getRequestDispatcher("").forward(req, resp);转发,不能使用重定向

可选案例:用户登陆,如果用户名和密码正确,则跳转到首页(转发),并且展示用户名,否则重新回到登陆页面

Session

javademo3

用户会话

服务器无法识别每一次HTTP请求的出处(不知道来自哪个终端-手机/电脑/pad),它只会接受一个请求信号,所以就存在一个问题:将用户的响应发送给其他人,必须有一种技术来让服务器知道请求来自哪,这就是会话技术

会话:就是客户端和服务器之间发生的一系列连续的请求和响应的过程,打开浏览器进行操作到关闭浏览器的过程

会话状态:指服务器和浏览器在会话过程中产生的状态信息,借助于会话状态,服务器能够把属于同一次会话的一系列请求和响应关联起来

实现会话有两种方式:

  • session(是内置对象)
  • cookie

为了区分会话我们需要做标识

关闭浏览器重新打开,sessionId就会变化,因为一个生命周期已经结束了

属于同一次会话的请求都有一个相同的标识符,sessionID

session 常用的方法:

String getId() 获取 sessionID

void setMaxINactiveInterval (int interval) 设置session 的失效时间,单位为秒

int getMaxInactiveInterval() 获取 session 的失效时间

void invalidate() 设置 session 立即失效

void setAttribute(String key,Object value) 通过键值对的形式来存储数据

Object getAttribute(String key) 通过键获取对应的数据

void removeAttribute(String key) 通过键删除对应的数据

登录案例记录
  • web.xml 配置时 servlet-mapping 中

/login 不能是/login.jsp

  • LoginServlet.java 中 使用注解,且 xml 中做了映射

@WebServlet("/LoginServlet") 名称要和文件名一致,否则tomcat服务无法启动

  • 当打开页面登录后,再打开一个网页,访问welcome,无法输出姓名,因为request一个周期很短,所以我们要使用session,只要不关闭浏览器,就不会销毁

使用session存储后,使用转发或者重定向(sendRedirect)就都可以了,因为我们不再依赖request

  • a标签发送的是get,所以 LogoutServlet 重写doGet ( )

Cookie

Cookie 是服务端在 HTTP 响应中附带传给浏览器的一个小文本文件,一旦浏览器保存了某个 Cookie,在之后的请求和响应过程中,会将此 Cookie 来回传递,这样就可以通过 Cookie 这个载体完成客户端和服务端的数据交互

Cookie

  • 创建Cookie,响应到客户端

客户端与服务端交互,应该使用 response

Cookie cookie = new Cookie("name","zhangsan");
不建议存中文
response.addCookie(cookie);
  • 读取Cookie
 Cookie[] cookies=request.getCookies();
    for(Cookie cookie: cookies){
    
    
//       out.write(cookie.toString());    
        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:new Cookie(name,“admin”)

​ response.addCookie(new Cookie(name,“adim”)) 存

Cookie[] cookies=request.getCookies();
for(Cookie cookie:cookies){
    
    
    if(cookie.getName().equals("name")){
    
    
        out.write("欢迎回来:"+cookie.getValue());
    }
}

生命周期:不随服务端的重启而销毁,客户端默认只要关闭浏览器就销毁,通过setMaxAge(int age)设置有效期,一旦设置有效期则不会受关闭影响,受时间限制

退出登录: setMaxAge(0)


JSP 内置对象作用域

4个内置对象

page、request、session、application

setAttribute、getAttribute

(Cookie 不是内置对象,session优先级当然高,不是一回事)

page 作用域: 对应的内置对象是 pageContext(它的范围叫做page)

request 作用域:对应的内置对象是 request

session 作用域:对应的内置对象是 session

application 作用域:对应的内置对象是 application

page < request < session < application

page只在当前页面有效

request 在一次请求内有效 (周期极短)

session 在一次会话内有效(关闭或打开新的浏览器销毁)

application 对应整个 web应用

  • 网站访问量统计
count.jsp
<%
    Integer count = (Integer) application.getAttribute("count");
    if (count == null) {
        count = 1;
        application.setAttribute("count", count);
    } else {
        count++;
        application.setAttribute("count", count);
    }

%>
您是第<%=count%>位

为什么不能是request?每次关闭网页时,打开的便是一个全新的request,从0开始;为什么不是session,关闭浏览器,打开的便是一个全新的session;所以要用application来存储到 tomcat 里,但是如果tomcat被关闭时,数据便又要从0开始了,最终方案是存到数据库中,每次关闭又打开,从数据库中读取就好了


EL 表达式

javademo4

Expression Language 表达式语言,替代 JSP页面中数据访问时的复杂编码,可以非常便捷的取出域对象(pageContext、request、session、application)中保存的数据,前提是一定要先 setAttribute,

EL 就相当于在简化 getAttribute

$(变量名) 变量名就是 setAttribute 对应的 key值

1、EL 对于4 中域对象的查找顺序:

pageContext -》 request -》session-》application

按上述顺序返回,找不到返回null

2、指定作用域查找

pageContext:${pageScope.name}

request:${requestScope.name}

session:${sessionScope.name}

application:${applicationScope.name}

javax.el.PropertyNotFoundException: 类型[com.thciwei.entity.User]上找不到属性[id]

没有get方法当然找不到id了;

这样写时 这是调用set方法

    <td>${user.id=3}</td>
       id=3 
 当address成为user一个属性时
 User user=new User(1,"李明",175.0,new Address(1,"小米"));
 <td>${user.address}</td>
 展示出的内容是com.thciwei.entity.Address@666e18ae
 并不是我们要的结果

我们这类情况下可以重写toString方法,如

  @Override
    public String toString() {
    
    
  return "User{" + "id=" + id + ",name=" + name + ",height=" + height + "}";
    }

但这个案例我们不需要这么多数据,可以点address的属性即可

<td>${user.address.value}</td>

反射机制研究示例

  <td>${user.id}</td>
  <td>${user.name}</td>

这里随便改一下

<td>${user.num}</td>
<td>${user.name}</td>

我们重写一下User中的getId方法

public Integer getNum(getId)()
{
   return id;
}

此时程序运行并不会报错,页面呈现的东西仍然是 id

在解析时,user.num中num

1.首字母变大写,Num,前面追加 get

2.找getNum方法,调用

<%

( (User)pageContext.getAttribute(“user”) ).getNum();

%>

原理其实是反射机制造成的

这里可以获得理解——它( ${user.id})不是在和属性绑定,而是在和方法绑定. 一个东西它不是访问属性(属性是私有的),访问的是方法


数据级联:

<%
//    request.setAttribute("name","tom");
//    request.getRequestDispatcher("el2.jsp").forward(request,response);
    User user=new User(1,"李明",175.0,new Address(1,"小米"));
    System.out.println(user.toString());
    pageContext.setAttribute("user",user);
%>
<table>
    <tr>
        <th>编号</th>
        <th>姓名</th>
        <th>身高</th>
        <th>地址</th>
    </tr>
    <tr>
<%--        <td>${user.id=3}</td>--%>
<%--      id=3  调用set方法--%>
        <td>${user.id}</td>
        <td>${user.name}</td>
        <td>${user.height}</td>
        <td>${user.address.value}</td>
    </tr>
</table>

${User[“id”]}

EL 执行表达式

&& || ! <> <= >= ==

&& and

|| or

! not

== eq

!= ne

< lt

gt >

<= le

ge>=

empty 判空,空为true:变量为null,长度为0的String,size为0的集合

not empty 取反不为空,符合逻辑

<table>
<tr>
    <th>学号</th>
    <th>姓名</th>
    <th>身高</th>
    <th>地址</th>

</tr>
<%
    List<User> list=(List<User>)request.getAttribute("list");
    for(User user:list){
        request.setAttribute("user",user);
%>
<tr>
    <td>${user.id}</td>
    <td>${user.name}</td>
    <td>${user.height}</td>
    <td>${user.address.value}</td>
</tr>
<%--${requestScope.list[0].id}--%>
<%
    }
%>
</table>

一定要再存入,request.setAttribute("user",user);

因为EL表达式

取出域对象(pageContext、request、session、application)中保存的数据,前提是一定要先 setAttribute,

EL 就相当于在简化 getAttribute

但是EL本身出现的目的就是为了减少出现 jsp和java 复杂包裹的问题,但EL表达式不能遍历,所以引入下面的内容


JSTL详解

这一部分展示是/user

JSP Standard Tag Library JSP 标准标签库,JSP 为开发者提供的一系列标签,使用这些标签可以完成一些逻辑处理,比如循环遍历集合,让代码更简洁,不再出现 JSP 脚本穿插的情况

实际开发中 EL 和 JSTL 结合起来使用,JSTL 负责逻辑处理,EL 负责展示数据

JSTL 的使用

1、需要导入 jar 包 (jstl.jar 、standard,jar)

在web里创建 lib,拷贝到 lib,(左上或右上)project struct中library中添加java 引入jar包,lib中能查看源码则成功,lib 一定要放在 WEB-INF中

2、在 JSP 页面开始的地方导入JSTL标签库

index.jsp中(类似引入js等库文件,下面是引入jstl核心标签库)

prefix是前缀,用一个字符去表示 jstl(核心标签库core一般用c表示)

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

3、在需要的地方使用

之前在User.java定义了User类,userServlet.java写了list<User>集合,添加了数据
<c:forEach items="${list}" var="user">
    <tr>
        <td>${user.id}</td>
        <td>${user.name}</td>
        <td>${user.height}</td>
        <td>${user.address.value}</td>
    </tr>
</c:forEach>

符号的意思

value --内容,

$ --request.getAttribute,

var=“ ” --变量名

JSTL优点:

1、提供统一的标签

2、可以用于编写各种动态功能

常用标签:

set、out、remove、catch

核心标签库

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
  • set:向域对象中添加数据
<%
request.setAttribute(key,value)
%>
<c:set var="name" value="tom" scope="request"></c:set>
${requestScope.name}
//不指定域时默认存到pageScope中,可以通过${pageScope.name}验证,从小到大,page-request-session-application
<%
    User user=new User(1,"张三",175.0,new Address(1,"科技园"));
    request.setAttribute("user",user);
%>
${user.name}
<hr/>
<c:set target="${user}" property="name" value="李四"></c:set>
${user.name}
  • out: 输出域对象中的内容
<c:set var="name" value="tom" ></c:set>
<c:out value="${name}"></c:out>
<c:out value="${names}" default="未定义"></c:out>

当不存在展示的数据时,out 方法可以展示default内容,而直接用${name}却做不到

  • remove:删除域对象中的数据
<c:remove var="name"></c:remove>
<c:out value="${name}" default="未定义"></c:out>
  • catch: 捕获异常
<c:catch var="error">
    <%
        int a=10/0;
    %>
</c:catch>
${error}
只显示java.lang.ArithmeticException: / by zero
  • 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>fal</c:otherwise>
</c:choose>
  • forEach: 迭代标签

主要功能是遍历数据

 <%
     List<String> list=new ArrayList<>();
     list.add("a");
     list.add("b");
     list.add("c");
     list.add("d");
     list.add("e");
     list.add("f");
     list.add("g");
     list.add("h");
     list.add("i");
     request.setAttribute("list",list);
 %>
<c:forEach items="${list}" var="str" varStatus="sta">(begin="2" end="3" step="2")
    ${sta.count}、${str}
</c:forEach>

给数据加序号可以用count

格式化标签库

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%
    request.setAttribute("date",new Date());
%>
<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
<fmt:formatNumber value="32145.23434" maxIntegerDigits="2" maxFractionDigits="3"></fmt:formatNumber>

函数标签库

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%
    request.setAttribute("info","java,C");
%>
${fn:contains(info,"Python")}<br/>   false
${fn:startsWith(info,"java")}<br/>   true
${fn:endsWith(info,"C")}<br/>        true
${fn:indexOf(info,"va")}<br/>  从第二位开始      2
${fn:replace(info, "C","Python" )}<br/>                                                  java,python
${fn:substring(info,2 ,3 )}<br/> 
从第二位截取到第三位,不包括3             va
${fn:split(info, ",")[0]}-${fn:split(info,",")[1]}
把字符串按下标分隔                      java-C

综合案例

form表单的属性

action URL 规定当提交表单时向何处发送表单数据

method get/post 规定用于发送 form-data 的 HTTP 方法。(提交表单的方式)

value是内容,name是表单提交时需要获得的名称

<form action="/user?method=update" method="post">
<form action="/user2">
    <input type="text" name="" value=""></input>
</form>
增删改查
add.jsp
<form action="/user2" method="post">
    编号:<input type="text" name="id"><br/>
    姓名:<input type="text" name="name"><br/>
    身高:<input type="text" name="height"><br/>
    <input type="submit" value="添加"><br/>
</form>
user2.java
public class User2 {
    
    
    private Integer id;
    private String name;
    private Double height;
    public User2(Integer id, String name, Double height) {
    
    
        this.id = id;
        this.name = name;
        this.height = height;
    }
    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 getHeight() {
    
    
        return height;
    }
    public void setHeight(Double height) {
    
    
        this.height = height;
    }
}
User2Servlet.java
@WebServlet("/user2")
public class User2Servlet extends HttpServlet {
    
    
    List<User2> list = new ArrayList<>();
    public User2Servlet(){
    
    
    list.add(new User2(1, "李明", 175.0));
    list.add(new User2(2, "万恶", 123.0));
    list.add(new User2(3, "我的", 233.0));
}
    //method=post
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String idStr = req.getParameter("id");
        String name = req.getParameter("name");
        String heightStr = req.getParameter("height");
        Integer id = Integer.parseInt(idStr);
        Double height = Double.parseDouble(heightStr);
        User2 user2 = new User2(id, name, height);
        list.add(user2);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
       // list.add(new User2(1, "李明", 175.0));
       //list.add(new User2(2, "万恶", 123.0));
       //list.add(new User2(3, "我的", 233.0));
        req.setAttribute("list", list);
   req.getRequestDispatcher("index.jsp").forward(req, resp);
    }
}

中文乱码的话在 Serlvet 中加入req.setCharacterEncoding(“UTF-8”)

list.add(new User2(1, "李明", 175.0));
list.add(new User2(2, "万恶", 123.0));
list.add(new User2(3, "我的", 233.0));

上述是绝对不能写在doGet( )中的,因为这样会导致表单会每次添加新数据的旧数据也会添加一遍

解决方法:添加到构造器里,构造器是优先于下面方法的执行的,并且构造器是只执行一次的,不会随着刷新再次执行;或者写在静态代码块中,同样只执行一次;都因为类只加载一次

    public static List<User2> list = new ArrayList<>();
static{
    
    
    list.add(new User2(1, "李明", 175.0));
    list.add(new User2(2, "万恶", 123.0));
    list.add(new User2(3, "我的", 233.0));
}

  • 删和查
index.jsp  
<c:forEach items="${list}" var="user">
        <tr>
            <td>${user.id}</td>
            <td>${user.name}</td>
            <td>${user.height}</td>
            <td>
<a href="/user2?method=delete&id=${user.id}">删除</a>
<%--                传的参可以自定义--%>
                <a>修改</a>
            </td>
        </tr>
    </c:forEach>

这里注意,我们可以通过传参数帮助 servlet 判断删除内容最后进行处理,我们传的参数都是可以自定义的

if(method==null){
method="findAll";
}
switch(method) {
    case "delete":
        String idStr=req.getParameter("id");
        Integer id=Integer.parseInt(idStr);
        list.remove(id);
        break;
    case "findAll":
        req.setAttribute("list",list);
      req.getRequestDispatcher("index.jsp").forward(req,resp);
        break;
        }

但这里我们并不能使用 list去删除行内容,我们观察User2类,数据是一个对象,把id传过去,自动找的是id,但面对的是一个对象,怎么会找得到呢

所以我们要用哈希map

@WebServlet("/user2")
public class User2Servlet extends HttpServlet {
    
    
    Map<Integer,User2> map = new HashMap<>();
public User2Servlet(){
    
    
    map.put(1,new User2(1, "李明", 175.0));
    map.put(2,new User2(2, "万恶", 123.0));
    map.put(3,new User2(3, "我的", 233.0));
}
    //method=post
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String idStr = req.getParameter("id");
        String name = req.getParameter("name");
        String heightStr = req.getParameter("height");
        Integer id = Integer.parseInt(idStr);
        Double height = Double.parseDouble(heightStr);
        User2 user2 = new User2(id, name, height);
      map.put(id,user2);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
String method=req.getParameter("method");
if(method==null){
    
    
    method="findAll";
}
switch(method) {
    
    
    case "delete":
        String idStr=req.getParameter("id");
        Integer id=Integer.parseInt(idStr);
        map.remove(id);
        resp.sendRedirect("/user2");
        break;
    case "findAll":
        req.setAttribute("list",map.values());
        req.getRequestDispatcher("index.jsp").forward(req,resp);
        break;
        }

    }
}

处理删除后的页面空白

重定向resp.sendRedirect("/user2");


index.jsp  
<c:forEach items="${list}" var="user">
        <tr>
            <td>${user.id}</td>
            <td>${user.name}</td>
            <td>${user.height}</td>
            <td>
<a href="/user2?method=delete&id=${user.id}">删除</a>
<a href="/user2?method=findById&id=${user.id}">修改</a>
            </td>
        </tr>
    </c:forEach>
update.jsp
<form action="/user2" method="post">
    编号:<input type="text" name="id" value="${user2.id}" readonly><br/>
    姓名:<input type="text" name="name" ><br/>
    身高:<input type="text" name="height"><br/>
    <input type="submit" value="修改"><br/>
</form>
User2Servlet.java
@WebServlet("/user2")
public class User2Servlet extends HttpServlet {
    
    
    Map<Integer, User2> map = new HashMap<>();

    public User2Servlet() {
    
    
        map.put(1, new User2(1, "李明", 175.0));
        map.put(2, new User2(2, "万恶", 123.0));
        map.put(3, new User2(3, "我的", 233.0));
    }

    //method=post
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
      String idStr = req.getParameter("id");
      String name = req.getParameter("name");
      String heightStr = req.getParameter("height");
        
      Integer id = Integer.parseInt(idStr);
      Double height = Double.parseDouble(heightStr);
      User2 user2 = new User2(id, name, height);
      map.put(id, user2);
      resp.sendRedirect("/user2");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String method = req.getParameter("method");
        if (method == null) {
    
    
            method = "findAll";
        }
        switch (method) {
    
    
            case "delete":
                String idStr = req.getParameter("id");
                Integer id = Integer.parseInt(idStr);
                map.remove(id);
                resp.sendRedirect("/user2");
                break;
            case "findAll":
                req.setAttribute("list", map.values());
                req.getRequestDispatcher("index.jsp").forward(req, resp);
                break;
            case "findById":
                idStr = req.getParameter("id");
                id = Integer.parseInt(idStr);
                req.setAttribute("user2", map.get(id));
                req.getRequestDispatcher("update.jsp").forward(req, resp);
                break;
        }

    }
}
实现的逻辑
<a href="/user2?method=findById&id=${user.id}">修改</a>
-------------------------------------------------
case "findById":
                idStr = req.getParameter("id");
                id = Integer.parseInt(idStr);
                req.setAttribute("user2", map.get(id));
--------------------------------------------------
User2 user2 = new User2(id, name, height);
  map.put(id, user2);
  resp.sendRedirect("/user2");
  //创造新的对象取代原对象

因为 map集合 的特性,当id不存在时可以自动添加新的对象,但是我们产生改的操作只是针对当前进行修改,不能有添加的能力,那么我们在 jsp 的 input 中要添加只读属性,限制对id的修改

编号:<input type="text" name="id" value="${user2.id}" readonly><br/>

过滤器

javademo5

Filter

功能

1、用来拦截传入的请求和传出的响应

2、修改或以某种方式处理正在客户端和服务端之间交换的数据流

如何使用?

与servlet类似,Filter 是 java Web提供的一个接口,开发者只需要定义一个类实现该接口即可

导包是 import javax.servlet.Filter ;

配置和链

login.jsp
<form action="/login" method="post">
    <input type="text" name="name">
    <input type="submit" name="提交">
</form>
CharacterFilter.java
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);
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    

    }
    @Override
    public void destroy() {
    
    

    }
}

注意导包 —— import javax.servlet.*;

正常来说我们只用实现接口的 doFilter 方法,其他两个有default前缀(默认方法),但是有的时候tomcat会报错,查看日志发现方法都实现才能解决问题

web.xml中配置 Filter(映射关系)

web.xml
<?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">
    <filter>
        <filter-name>charcater</filter-name>
        <filter-class>com.thciwei.filter.CharacterFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>charcater</filter-name>
        <url-pattern>/login</url-pattern>
        <url-pattern>/test</url-pattern>
    </filter-mapping>
</web-app>

注意:doFilter 方法中处理完业务逻辑之后,必须添加 **filterChain.doFilter(servletRequest,servletResponse);**否则请求/响应无法向后传递,一直停留在过滤器中

因为客户端 发送被过滤器拦截,当过滤器有多个时形成链条状,通过链条不断联通最后送到 服务端,所以一定要用 filterChain

生命周期

当 Tomcat 启动时,通过反射机制调用 Filter 的无参构造函数创建实例化对象,同时调用 init 方法实现初始化,doFilter 方法调用多次,当Tomcat 服务关闭的时候,调用 destroy 来销毁 Filter 对象

无参构造函数:只调用一次,当Tomcat 启动时调用 (Filter一定进行配置)

doFilter:调用多次,访问 Filter 的业务逻辑都写在 Filter中(每次访问都会调用方法)

destroy: 只调用一次,Tomcat关闭时调用

顺序

同时配置多个 Filter,Filter 的调用顺序是由 web.xml 中的配置顺序来决定的,写在上面的配置先调用,因为web.xml 是从上到下顺序读取的

<filter>
     <filter-name>charcater</filter-name>
     <filter-class>com.thciwei.filter.CharacterFilter</filter-class>
 </filter>
 <filter-mapping>
     <filter-name>charcater</filter-name>
     <url-pattern>/login</url-pattern>
     <url-pattern>/test</url-pattern>
 </filter-mapping>
<filter>
    <filter-name>my</filter-name>
    <filter-class>com.thciwei.filter.MyFilter</filter-class>
</filter>
 <filter-mapping>
     <filter-name>my</filter-name>
     <url-pattern>/login</url-pattern>
 </filter-mapping>

1、CharacterFilter

2、MyFilter

可以通过注解的方式来简化web.xml 的配置,

LoginServlet.java
@WebFilter("/login")
public class LoginServlet extends HttpServlet {
    
    
 
}

等于

<filter>
     <filter-name>charcater</filter-name>
     <filter-class>com.thciwei.filter.CharacterFilter</filter-class>
 </filter>
 <filter-mapping>
     <filter-name>charcater</filter-name>
     <url-pattern>/login</url-pattern>
 </filter-mapping>

业务场景特殊时需要控制过滤顺序时才使用web.xml 配置

实际开发中 Filter 的使用场景:

1、统一处理中文乱码

2、屏蔽敏感词

@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);

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    

    }

}
@WebServlet("/test")
public class TestServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
    String name = (String) req.getAttribute("name");
        System.out.println("servlet" + name);
    }
}

不能用getParameter(),需要setAttribute(" “, ),在servlet中再getAttribute(” ")

3、控制资源的访问权限

登录状态才能下载——过滤器检查session是否有登录信息

LoginServlet.java
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String name = req.getParameter("name");
        String password = req.getParameter("password");
        if (name.equals("admin") && password.equals("123")) {
    
    
            HttpSession session = req.getSession();
            session.setAttribute("name", name);
            resp.sendRedirect("/download.jsp");
        }
    }
}
login.jsp
<form action="/login" method="post">
    <input type="text" name="name"><br/>
    <input type="text" name="password"><br/>
    <input type="submit" value="登录"><br/>
</form>
DownloadFilter.java
@WebFilter("/download.jsp")
public class DownloadFilter implements Filter {
    
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
        HttpServletRequest request=(HttpServletRequest)servletRequest;
        HttpServletResponse response=(HttpServletResponse)servletResponse;
        HttpSession session=request.getSession();
        String name=(String)session.getAttribute("name");
        if(name==null){
    
    
            response.sendRedirect("/login.jsp");
        }else{
    
    
            filterChain.doFilter(servletRequest,servletResponse);
        }

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    

    }
}
download.jsp
<a href="">资源1</a>
<a href="">资源2</a>
<a href="">资源3</a>

因为没有downloadServlet,所以过滤器通过映射可以间接访问download.jsp


文件上传下载

上传
  • JSP

1、input 的 type 设置为 file

2、form表单的 method 设置 post,get请求会将文件名传给服务端,而不是文件本身

3、form表单的 enctype 设置 multipart/form-data,以二进制的形式传输数据

  • Servlet

在WEB-INF中添加lib 包含 commons-io和commons-fileupload的jar包(Apache下载)

fileupload 组件可以将所有的请求都解析成 Fileteam对象,可以通过 Fileteam对象的操作完成上传,面向对象的思想

upload.jsp
<form enctype="multipart/form-data" action="/upload" method="post">
    <input type="text" name="desc"><br/>
    <input type="file" name="text">
    <input type="submit" value="上传">
</form>
uploadServlet.java
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        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(""+value);
                }else{
    
    
          String fileName=fileItem.getName();
          long size=fileItem.getSize();
                    System.out.println(fileName+":"+size+"Byte");
 InputStream inputStream=fileItem.getInputStream();
           String path = req.getServletContext().getRealPath("file/"+fileName);
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();
        }

    }
}

我们应该用字节流读取,而不是字符流,这样不会破坏内部数据的结构,并帮助我们还原

javademo5

下载

报错后可以在工具栏 build 中 rebuild重新打包一下

download.jsp
<body>
<a href="/download?type=png">1.png</a>
<a href="/download?type=txt">test.txt</a>
</body>
DownloadServlet.java
@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 = "";
        switch (type) {
    
    
            case "png":
                fileName = "1.png";
                break;
            case "txt":
                fileName = "test.txt";
                break;
        }
        //设置响应方式
    resp.setContentType("application/x-msdownload");
        //设置下载之后的文件名
    resp.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        //获取输出流
  OutputStream outputStream = resp.getOutputStream();
       String path = req.getServletContext().getRealPath("file/" + fileName);
 InputStream inputStream = new FileInputStream(path);
        int temp = 0;
        while ((temp = inputStream.read()) != -1) {
    
    
            outputStream.write(temp);
        }
        inputStream.close();
        outputStream.close();

    }
}

在web文件夹中新建 file 文件夹 来模拟下载


Ajax

javademo6

大致

Asynchronous JavaScript And XML: 异步的 JavaSvript 和 XML

AJAX 不是新的新的编程,指的是一种交互方式,异步加载,客户端和服务器的数据交互更新在局部页面的技术,不需要刷新整个页面(局部刷新)

优点:

1、局部刷新,效率更高

2、用户体验更好

基于 jQuery 的 Ajax

在web中新建js文件夹,添加 jquery-3.3.1.min.js

<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
    $(function () {
      
      
            alert("123")
        }
    )
</script>

检查是否成功引入,未显示123,打开开发者工具查看报错,重加载检查 network中报红,复制 url检查

dataType 是服务器返回的类型

不能用表单提交请求,改用 jQuery 方式动态绑定事件来提交(表单提交是传统同步加载)

Servlet 不能跳转到 JSP,只能将数据返回

test.jsp
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
       var btn = $("#btn");//id选择器,拿到button对象
                btn.click(function () {
                    $.ajax({
                        url: '/test',
                        type: 'post',
                        data: 'id=1',
                        dataType: 'text',
                        success: function (data) {
             var text=$("#text");
             text.before("<span>"+data+"<span><br/>")
                        }
                    })
                });
            }
        )
    </script>
</head>
<body>
<input id="text" type="text"><br/>
<input id="btn" type="button" value="提交">
</body>
</html>
TestServlet.java
@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 World";
//       req.setAttribute("str",str);
//        req.getRequestDispatcher("test.jsp").forward(req,resp);
        resp.getWriter().write(str);
    }
}

var btn = $("#btn"); id选择器,拿到button对象

传统的 WEB 数据交互 对比 AJAX 数据交互

  • 客户端请求的方式不同:

传统,浏览器发送同步请求 (form、a)

AJAX,异步引擎对象发送异步请求

  • 服务器响应的方式不同:

传统,响应一整个 JSP 页面(视图)

AJAX,响应需要的数据

  • 客户端处理方式不同:

传统,需要等待服务器完成响应并且重新加载整个页面之后,用户才能进行后续的操作

AJAX,动态更新页面中的局部内容,不影响用户的其他操作

基于 jQuery 的Ajax语法

$.ajax({属性})

常见的属性参数:

url:请求的后端服务地址

type:请求方式,默认 get

data:请求参数

dataType:服务器返回的数据类型,text/json

success: 请求成功的回调函数

error: 请求失败的回调函数

complete:请求完成的回调函数(无论成功失败都会调用)

JSON

javascript Object Notation,一种轻量级数据交互格式,完成 js与 java 等后端开发语言对象数据之间的转换

客户端与服务器之间传递对象数据,需要用 JSON 格式

User.java
public class User {
    
    
    private Integer id;
    private String name;
    private Double score;
    public User(Integer id, String name, Double score) {
    
    
        this.id = id;
        this.name = name;
        this.score = score;
    }
    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;
    }
}

   User user=new User(1,"李明",23.0);
json格式
var user={
    
    
id:1,
name:'李明',
score:23.0
}

使用 json 转化数据

<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
    
    
          var btn = $("#btn");//id选择器,拿到button对象
                btn.click(function () {
    
    
                    $.ajax({
    
    
                        url: '/test',
                        type: 'post',
                        data: 'id=1',
                        dataType: 'json',
                        success: function (data) {
    
    
                          $("#id").val(data.id);
                          $("#name").val(data.name);
                          $("#score").val(data.score);
                        },
                        error: function () {
    
    
                            alert("服务器维护中...")
                        },
                        complete: function () {
    
    
                            alert("请求成功!")
                        },
                    })
                });
            }
        )
    </script>
</head>
<body>
编号:<input id="id" type="text"><br/>
姓名:<input id="name" type="text"><br/>
成绩:<input id="score" type="text"><br/>
<input id="btn" type="button" value="提交">
</body>
</html>
-------------------------------------------
@WebServlet("/test")
public class TestServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        User user = new User(1, "李明", 23.1);
        resp.setCharacterEncoding("UTF-8");
//将java对象转成 JSON 格式
        JSONObject jsonObject = JSONObject.fromObject(user);
        resp.getWriter().write(jsonObject.toString());
    }
}

案例

省市区级联

$(dom) 工厂函数,相当于domcument.getElementById(dom)

location.jsp
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
            //修改省份
            $("#province").change(function () {
                var id = $(this).val();
                $.ajax({
                    url: '/location',
                    type: 'post',
                    data: 'id=' + id + "&type=province",
                    dataType: 'JSON',
                    success: function (data) {
                        console.log(data)
                        var context = "";
                        var cities = data.cities;
                        for (var i = 0; i < cities.length; i++) {
                            context += "<option>" + cities[i] + "</option>";
                        }
                        $("#city").html(context);
                        context = "";
                        var areas = data.areas;

                        for (var i = 0; i < areas.length; i++) {
                            context += "<option>" + areas[i] + "</option>"
                        }
                        $("#area").html(context);
                    }
                })
            })
            //修改城市
            $("#city").change(function () {
                var id = $(this).val();
                $.ajax({
                    url: '/location',
                    type: 'post',
                    data: 'id=' + id + "&type=city",
                    dataType: 'JSON',
                    success: function (data) {
                        var context = "";
                        for (var i = 0; i < data.length; i++) {
                            context += "<option>" + data[i] + "</option>"
                        }
                        $("#area").html(context);
                    }
                })
            })
        });
    </script>
</head>
<body>
省:<select id="province">
    <option value="陕西省">陕西省</option>
    <option value="河南省">河南省</option>
    <option value="江苏省">江苏省</option>
</select>
市:<select id="city">
    <option value="西安市">西安市</option>
    <option value="宝鸡市">宝鸡市</option>
    <option value="渭南市">渭南市</option>
</select>
区:<select id="area">
    <option>雁塔区</option>
    <option>莲池区</option>
    <option>到汉区</option>
</select>
</body>
</html>
Location.java
public class Location {
    
    
    private List<String> cities;
    private List<String> areas;
    public List<String> getCities() {
    
    
        return cities;
    }
    public void setCities(List<String> cities) {
    
    
        this.cities = cities;
    }
    public List<String> getAreas() {
    
    
        return areas;
    }
    public void setAreas(List<String> areas) {
    
    
        this.areas = areas;
    }
}

纯用集合实现

LocationServlet.java
@WebServlet("/location")
public class LocationServlet extends HttpServlet {
    
    
 private static Map<String, List<String>> cityMap;
 private static Map<String, List<String>> provinceMap;
    static {
    
    
        cityMap = new HashMap<>();
        List<String> areas = new ArrayList<>();
        areas.add("雁塔区");
        areas.add("莲湖区");
        areas.add("新城区");
        cityMap.put("西安市", areas);
        //西安
        areas = new ArrayList<>();
        areas.add("陈仓区");
        areas.add("清滨区");
        areas.add("新城区");
        cityMap.put("宝鸡市", areas);
        //渭南
        areas = new ArrayList<>();
        areas.add("临渭区");
        areas.add("高新区");
        cityMap.put("渭南市", areas);
        //郑州
        areas = new ArrayList<>();
        areas.add("郑州A");
        areas.add("郑州B");
        cityMap.put("郑州市", areas);
        //洛阳
        areas = new ArrayList<>();
        areas.add("洛阳A");
        areas.add("洛阳B");
        cityMap.put("洛阳市", areas);

        provinceMap = new HashMap<>();
        List<String> cities = new ArrayList<>();
        cities.add("西安市");
        cities.add("宝鸡市");
        cities.add("渭南市");
        provinceMap.put("陕西省", cities);
        cities = new ArrayList<>();
        cities.add("郑州市");
        cities.add("石家庄市");
        cities.add("保定市");
        provinceMap.put("河南省", cities);
        cities = new ArrayList<>();
        cities.add("南京市");
        cities.add("开封市");
        cities.add("定州市");
        provinceMap.put("江苏省", cities);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        resp.setCharacterEncoding("UTF-8");
        String type = req.getParameter("type");
        String id = req.getParameter("id");

        switch (type) {
    
    
            case "city":
                List<String>  areas= cityMap.get(id);
    JSONArray jsonArray = JSONArray.fromObject(areas);
               resp.getWriter().write(jsonArray.toString());
                break;
            case "province":
       List<String> cities= provinceMap.get(id);
                String city = cities.get(0);
       List<String> cityAreas=cityMap.get(city);
       Location location=new Location();
       location.setAreas(cityAreas);
       location.setCities(cities);
JSONObject jsonObject=JSONObject.fromObject(location);
              resp.getWriter().write(jsonObject.toString());
                break;
        }
    }
}

JSONArray | JSONObject,前者应对集合的格式转化,后者应对对象(location封装了两个集合)的格式转换


JDBC

javademo7

Java DataBase Connectivity 是一个独立于特定数据库的管理系统,通用的 SQL 数据库存取和操作的公共接口。定义了一组标准,为访问不同数据库提供了统一的途径

JDBC体系结构

JDBC 接口包括两个层面:

  • 面向应用的 API,供程序员调用
  • 面向数据库的 API,供厂商开发数据库的驱动程序

JDBC API

提供者:Java 官方

内容:供开发者调用的接口

java.sql 和 javax.sql

  • DriverManager 类
  • Connection 接口
  • Statement 接口
  • ResultSet 接口

DriverManager

提供者:Java官方

作用:管理不同的 JDBC 驱动

JDBC驱动

提供者:数据库厂商

作用:负责连接不同的数据库

JDBC的使用

1、加载数据库驱动,java 程序和数据库之间的桥梁

2、获取 Connection,Java 程序与数据库的一次连接

3、 创建 Statement 对象,由 Connection产生,执行SQL语句

4、(查询),如果需要接受返回值,创建 ResultSet 对象,保存 Statement

执行之后所查询到的结果

简单来说,驱动是通信的基站,Connection是拨号的一次次请求

public class Test {
    
    
    public static void main(String[] args) {
    
    

        try {
    
    
            //加载驱动
            //反射获取运行时类
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取连接
            String url = "jdbc:mysql://localhost:3306/sys?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false";
            String user = "root";
            String password = "thciwei";
            Connection connection = DriverManager.getConnection(url, user, password);
            //System.out.println(connection);
            //String sql="insert into student(name,score,birthday)values('张三',78,'2019-01-01')";
            //String sql="update student set name='李四'";
            //String sql="delete from student";
   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);
                Date date = resultSet.getDate(4);
 System.out.println(id + "-" + name + "-" + score + "-" + date);
            }
            //statement.executeUpdate(sql);

        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }


}

需处理捕获异常 try catch (SQLException e)

加载驱动时 使用反射获取运行时类

Class.forName(“com.mysql.cj.jdbc.Driver”);

获取连接会遇到 时区中文乱码ssl 等问题

String url = “jdbc:mysql://localhost:3306/sys?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false”;

遍历表

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);
    Date date = resultSet.getDate(4);
    System.out.println(id + "-" + name + "-" + score + "-" + date);
}

PreparedStatement

Statement的子类,提供了 SQL 占位符的功能

使用 Statement 进行开发有两个问题:

1、需要频繁拼接 String 字符串,出错率较高

2、存在 SQL 注入的风险

String name = "lisi";
String mypassword="000";
String sql="select * from student where name='"+name+"'and  password='"+mypassword+"'";
登录成功!
String mypassword="123'or'1'='1"
同样登录成功,1=1恒成立,SQL注入了

SQL 注入:利用某些系统没有对用户输入的信息进行充分检测,在用户输入的数据中注入非法的 SQL 语句,从而利用系统的 SQL 引擎完成恶意行为的做法。

使用占位符 ?

   int id=50;
   String name = "lisi";
   String mypassword = "000";
            String sql = "select * from student where name = ? and password = ? and id = ?";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
           preparedStatement.setString(1, name);
           preparedStatement.setString(2, mypassword);
           preparedStatement.setInt(3,id);
            ResultSet resultSet = preparedStatement.executeQuery();

set 方法(第几个?,替换值)

Servlet+JSP+JDBC案例

javademo8

   String url = "jdbc:mysql://localhost:3306/sys?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false";

idea集成数据库右键modify table 可查看数据类型

idea DB按钮更新数据库

数据库设置好 id 的主键自增

准备

写测试类测试 JDBC;检查配置Tomcat ,/ 和浏览器

开始

结构

数据库设计

定义一个类去对应数据库中的数据类型

import java.util.Date;
public class Student {
    
    
private Integer id;
private Double score;
private String name;
private Date birthday;

    public Student(Integer id,String name, Double score , Date birthday) {
    
    
        this.id = id;
        this.score = score;
        this.name = name;
        this.birthday = birthday;
    }
get and set方法

写测试类测试 JDBC后

构建我们的 servlet,准备增删查改的请求响应处理

@WebServlet("/student")
public class StudentServlet extends HttpServlet {
    
    
    private StudentRespository studentRespository = new StudentRespository();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String method = req.getParameter("method");
        if (method == null) {
    
    
            method = "findAll";
        }
        switch (method) {
    
    
            case "findAll":
                //返回视图+数据
                List<Student> list = studentRespository.findAll();
                req.setAttribute("list", list);
                req.getRequestDispatcher("index.jsp").forward(req, resp);
                break;
            case "delete":
                String idStr = req.getParameter("id");
                Integer id = Integer.parseInt(idStr);
                studentRespository.deleteById(id);
                resp.sendRedirect("/student");
                break;
            case "findById":
                idStr = req.getParameter("id");
                id = Integer.parseInt(idStr);
                req.setAttribute("student", studentRespository.findById(id));
                req.getRequestDispatcher("update.jsp").forward(req, resp);
                break;
        }

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        String method = req.getParameter("method");
        switch (method) {
    
    
            case "add":
         String name = req.getParameter("name");
         String scoreStr = req.getParameter("score");
         Double score = Double.parseDouble(scoreStr);
                studentRespository.add(name, score);
                resp.sendRedirect("/student");
                break;
            case "update":
                String idStr = req.getParameter("id");
                Integer id = Integer.parseInt(idStr);
                name = req.getParameter("name");
                scoreStr = req.getParameter("score");
                score = Double.parseDouble(scoreStr);
                resp.sendRedirect("/student");
           studentRespository.update(id, name, score);
                break;
        }

    }
}

使用过滤器处理中文乱码

@WebFilter("/student")
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);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    

    }
}

构建方法类

操作数据库

findAll方法查询所有

public class StudentRespository {
    
    
    public List<Student> findAll() {
    
    
        List<Student> list = new ArrayList<>();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
    
    

            connection = JDBCTools.getConnection();
            String sql = "select * from student";
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            Student student = null;
            while (resultSet.next()) {
    
    
                Integer id = resultSet.getInt(1);
                String name = resultSet.getString(2);
                Double score = resultSet.getDouble(3);
                Date date = resultSet.getDate(4);
                student = new Student(id, name, score, date);
                list.add(student);
            }
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
JDBCTools.release(connection, preparedStatement, resultSet);

        }

        return list;
    }

    public void add(String name, Double score) {
    
    
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
    
    
            connection = JDBCTools.getConnection();
            String sql = "insert into student(name,score,birthday)values(?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, name);
            preparedStatement.setDouble(2, score);
            preparedStatement.setDate(3, new Date(1));
            preparedStatement.executeUpdate();

        } catch (SQLException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
JDBCTools.release(connection, preparedStatement, null);

        }
    }

    public void deleteById(Integer id) {
    
    
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
    
    
            connection = JDBCTools.getConnection();
            String sql = "delete from student where id = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, id);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
 JDBCTools.release(connection, preparedStatement, null);
        }

    }

    public Student findById(Integer id) {
    
    
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Student student = null;
        try {
    
    
            connection = JDBCTools.getConnection();
            String sql = "select * from student where id = ?";
 preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, id);
 resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
    
    
                Integer id2 = resultSet.getInt(1);
                String name = resultSet.getString(2);
                Double score = resultSet.getDouble(3);
                Date date = resultSet.getDate(4);
         student = new Student(id, name, score, date);
            }
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
        return student;
    }

    public void update(Integer id, String name, Double score) {
    
    
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
    
    
            connection = JDBCTools.getConnection();
            String sql = "update student set name = ?,score = ?,birthday = ? where id = "+id;
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, name);
            preparedStatement.setDouble(2, score);
            preparedStatement.setDate(3, new Date(1));
            preparedStatement.executeUpdate();

        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }


}

finally释放资源借助 util 工具类节省代码

主页展示

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<body>
<h1>管理系统</h1>
<table>
    <tr>
        <th>姓名</th>
        <th>编号</th>
        <th>成绩</th>
        <th>生日</th>
    </tr>
    <c:forEach items="${list}" var="student">
    <tr>
        <td>${student.name}</td>
        <td>${student.id}</td>
        <td>${student.score}</td>
        <td>${student.birthday}</td>
        <td>
            <a href="/student?method=delete&id=${student.id}">删除</a>
            <a href="/student?method=findById&id=${student.id}">修改</a>
        </td>
    </tr>
    </c:forEach>

</table>
</body>

添加数据

action处传参

<form action="/student?method=add" method="post">
    姓名:<input type="text" name="name"><br/>
    成绩:<input type="text" name="score"><br/>
    <input type="submit" value="提交">
</form>

修改数据

设置value ,把更新数据传回界面

<form action="/student" method="post">
    编号:<input type="text" name="id" value="${student.id}" readonly><br/>
    姓名:<input type="text" name="name" value="${student.name}"><br/>
    成绩:<input type="text" name="score" value="${student.score}"><br/>
    <input type="hidden" name="method" value="update">
    <input type="submit" value="修改">
</form>

封装工具类 util

staitc 的好处,不用new 对象,直接名称调用方法

release 方法哪个值不用,写成null

public class JDBCTools {
    
    
    private static Connection connection;
    private static String url = "jdbc:mysql://localhost:3306/sys?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false";
    private static String user = "root";
    private static String password = "thciwei";

    static {
    
    
        try {
    
    
            Class.forName("com.mysql.cj.jdbc.Driver");

        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
    
    
        try {
    
    
            connection = DriverManager.getConnection(url, user, password);
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }
        return connection;
    }

    public static void release(Connection connection, Statement statement, ResultSet resultSet) {
    
    
        try {
    
    
            if (connection != null) {
    
    
                connection.close();
            }
            if (statement != null) {
    
    
                statement.close();
            }
            if (resultSet != null) {
    
    
                resultSet.close();
            }
        } catch (SQLException e) {
    
    
            e.printStackTrace();
        }
    }
}

数据库连接池

javademo7

JDBC 开发流程

  • 加载驱动
  • 建立数据库连接 (Connection)
  • 执行SQL语句(Statement)
  • ResultSet 接受结果集(查询)
  • 断开连接,释放资源

数据库连接对象是通过 DriverManager 来获取的,每次获取都需要向数据库申请获取连接,验证用户名和密码

执行完SQL语句后断开连接,这样的方式会造成资源的浪费,数据连接资源没有得到很好的重复利用(每次获取连接对象后又断开,每次都要重新申请,浪费资源)

可以使用数据库连接池解决这一问题

数据库连接池的基本思想就是为数据库建立一个缓冲池,预先向缓冲池中放入一定数量的连接对象,当需要获取数据库连接的时候,只需要从缓冲池中取出一个对象,用完之后再放回到缓冲池中,供下一次请求使用,做到了资源的重复利用,允许程序重复使用一个现有的数据库连接对象。而不需要重新创建

当数据库连接池中没有空闲的连接时,新的请求就会进入等待队列,等待其他线程释放连接(多线程)

数据库连接池实现

JDBC 的数据库连接池使用 javax.sql.DataSource 接口来完成的,DataSource 是 Java 官方提供的接口,使用的时候开发者并不需要自己来实现接口,可以使用第三方的工具,C3P0 是一个常用的第三方实现,实际开发中直接使用C3P0 即可完成数据库连接池的操作

1、导入 jar 包

传统方式拿到的 connection

com.mysql.cj.jdbc.ConnectionImpl@27c20538

C3P0 拿到的 connection

com.mchange.v2.c3p0.impl.NewProxyConnection@28c4711c

两种结果的原因实际是多态,C3P0面向接口编程,所以

传统方式 connection.close() 实质是关闭释放资源;

C3P0 connection.close() 实质是还回到数据库连接池中

实际还是多态在起作用

public class DataSourceTest {
    
    
    public static void main(String[] args){
    
    
        //创建C3P0
        try {
    
    
            ComboPooledDataSource dataSource=new ComboPooledDataSource();
            dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/sys?useUnicode=true&serverTimezone=GMT&characterEncoding=UTF-8&useSSL=false");
            dataSource.setUser("root");
            dataSource.setPassword("thciwei");
            Connection connection =dataSource.getConnection();
            System.out.println(connection);
            connection.close();
            //还回到数据库连接池中
        } catch (PropertyVetoException e) {
    
    
            e.printStackTrace();
        }catch (SQLException e){
    
    
            e.printStackTrace();
        }
    }
}

实际开发,将C3P0 的配置信息定义在 xml文件中,Java 程序只需要加载配置文件即可完成数据库连接池的初始化操作

1、文件名是写死的, c3p0-config.xml,文件放到src /java里

2、初始化 ComboPooledDataSource("name-config的属性值“);

xml文件中&用 &amp; 转义字符代替

 c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>

	<named-config name="testc3p0">
		<!-- 指定连接数据源的基本属性 -->
		<property name="user">root</property>
		<property name="password">thciwei</property>
		<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/sys?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC&amp;useSSL=false</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>
DataSourceTest.java
public class DataSourceTest {
    
    
    public static void main(String[] args){
    
    
        //创建C3P0
        try {
    
    
            ComboPooledDataSource dataSource=new ComboPooledDataSource("testc3p0");
            Connection connection =dataSource.getConnection();
            System.out.println(connection);
            connection.close();
            //还回到数据库连接池中
        }catch (SQLException e){
    
    
            e.printStackTrace();
        }
    }
}

idea下连接池的问题

c3p0-config.xml 的位置很重要,否则idea无法读取配置文件,我们应该放在 src/main/resources


DBUtils

DBUtils 可以帮助开发者完成数据的封装 (结果集到 java 对象的映射)

1、导入 jar 包

ResultHandler 接口是用来处理结果集,可以将查询到的结果集转换成 Java对象,提供了 4 种实现类

  • BeanHandler 将结果集映射成 Java 对象 Student
  • BeanListHandler 将结果集映射成 List集合 List
  • MapHandler 将结果集映射成 Map对象
  • MapListHandler 将结果集映射成 MapList 结合

什么是结果集

比如我们SQL语句

select * from student where id = 30

红色框中就是结果集,即我们要的数据

java对象

public class DBUtilsTest {
    
    
    private static ComboPooledDataSource dataSource;

    static {
    
    
        dataSource = new ComboPooledDataSource("testc3p0");
    }

    public static void main(String[] args) {
    
    
        Student student = findById();//普通
        System.out.println(student);
        Student student1 = findById1(32);//DBUtils
        System.out.println(student1);
    }

    public static Student findById1(Integer id) {
    
    
        Student student = null;
        Connection connection = null;

        try {
    
    
            connection = dataSource.getConnection();
            String sql = "select * from student where id = ?";
        QueryRunner queryRunner = new QueryRunner();
        student = queryRunner.query(connection, sql, new BeanHandler<>(Student.class), id);
       
        } 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;
    }

}

List集合

  public static Student findById1(Integer id)  
        try{
    
    
            connection = dataSource.getConnection();
          String sql = "select * from student";
          QueryRunner queryRunner = new QueryRunner();
 System.out.println( queryRunner.query(connection, sql, new BeanListHandler<>(Student.class)));
        }

Map对象

System.out.println( queryRunner.query(connection, sql, new MapHandler(),id));
键值对形式:{
    
    id=32, name=王五, score=80.0, birthday=2019-12-10}

MapList对象

 String sql = "select * from student";
List<Map<String,Object>> list=queryRunner.query(connection, sql, new MapListHandler());
            System.out.println(list);

根据数据库构建的Student类,注意有无参构造

无参构造及原理

为什么要有无参构造,才能不报错,这跟我们的工具类有关系,new BeanHandler等对象通过 反射机制获得样式,通过无参构造并创造我们的数据对象,如本例子中的Student类,然后把数据库中的对应数据赋给这个对象 (源码中的 return this)

此外方法使用了动态参数 Object…params,以便于我们传参,比如上面的 findById1(Integer id ,String name,Double score) 后

我们只需要改变

 student = queryRunner.query(connection, sql, new BeanHandler<>(Student.class), id,name,score);
Student.java
public class Student {
    
    
    private Integer id;
    private String name;
    private Double score;
    private Date birthday;
//get and set 方法省略
    public Student(){
    
    

    }
    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 +
                '}';
    }
}

项目实战

library

DROP TABLE IF EXISTS `book`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
 SET character_set_client = utf8mb4 ;
CREATE TABLE `book` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `author` varchar(20) DEFAULT NULL,
  `publish` varchar(20) DEFAULT NULL,
  `pages` int(10) DEFAULT NULL,
  `price` float(10,2) DEFAULT NULL,
  `bookcaseid` int(10) DEFAULT NULL,
  `abled` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_ieh6qsxp6q7oydadktc9oc8t2` (`bookcaseid`),
  CONSTRAINT `FK_ieh6qsxp6q7oydadktc9oc8t2` FOREIGN KEY (`bookcaseid`) REFERENCES `bookcase` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=107 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `book`
--

LOCK TABLES `book` WRITE;
/*!40000 ALTER TABLE `book` DISABLE KEYS */;
INSERT INTO `book` VALUES (1,'解忧杂货店','东野圭吾','电子工业出版社',102,27.30,9,0),(2,'追风筝的人','卡勒德·胡赛尼','上海人民出版社',230,33.50,3,0),(3,'人间失格','太宰治','作家出版社',150,17.30,1,1),(4,'这就是二十四节气','高春香','电子工业出版社',220,59.00,3,1),(5,'白夜行','东野圭吾','南海出版公司',300,27.30,4,1),(6,'摆渡人','克莱儿·麦克福尔','百花洲文艺出版社',225,22.80,1,1),(7,'暖暖心绘本','米拦弗特毕','湖南少儿出版社',168,131.60,5,1),(8,'天才在左疯子在右','高铭','北京联合出版公司',330,27.50,6,1),(9,'我们仨','杨绛','生活.读书.新知三联书店',89,17.20,7,1),(10,'活着','余华','作家出版社',100,100.00,6,1),(11,'水浒传','施耐庵','三联出版社',300,50.00,1,1),(12,'三国演义','罗贯中','三联出版社',300,50.00,2,1),(13,'红楼梦','曹雪芹','三联出版社',300,50.00,5,1),(14,'西游记','吴承恩','三联出版社',300,60.00,3,1);
/*!40000 ALTER TABLE `book` ENABLE KEYS */;
UNLOCK TABLES;

MVC

是一种开发模式,将程序分层的一种思想

M: Model 业务数据(service、repository、entity[实体类] )

V: View 视图 ( JSP、html、APP客户端)

C: Controller 控制 (Servlet、Handler、Action)

请求进入 Java Web应用后, Controller接收该请求,进行业务逻辑处理,最终将处理的结果再返回给用户 (View+Model)

​ 响应 交互 数据库

Controller–》 Service --> Repository

请求进入 Controller,进行业务处理,从 Controller中将 Model带到View中响应给用户

项目

reader 信息是从session取的,服务器重启后session便消失了,程序变会报错

case "addBorrow":
    String bookidStr = req.getParameter("bookid");
    Integer bookid = Integer.parseInt(bookidStr);
    HttpSession session = req.getSession();
    Reader reader = (Reader) session.getAttribute("reader");

所以我们必须有一个登录状态的读者和管理员

引入过滤器

@WebFilter("/book")
public class ReaderFilter implements Filter {
    
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
        //判断是否有读者登录
        HttpSession session = ((HttpServletRequest) servletRequest).getSession();
        Reader reader = (Reader) session.getAttribute("reader");
        if (reader == null) {
    
    
            ((HttpServletResponse) servletResponse).sendRedirect("login.jsp");
        } else {
    
    
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    

    }
}

注意一些情况下是有值在进行,

if (resultSet.next())

遍历情况下才是

while(resultSet.next())

完结:撒花

猜你喜欢

转载自blog.csdn.net/thciwei/article/details/121753089
今日推荐