文章目录

  • 一 web引言
    • 1.1 生活中的上网方式
    • 1.2 Web服务器
    • 1.3 Web相关概念
  • 二 Tomcat
    • 2.1 Tomcat安装与配置
  • 三 Web项目
    • 3.1Web项目分类
    • 3.2 tomcat部署项目
    • 3.3 IDEA配置Tomcat
    • 3.4 idea中的web项目的内容部署到tomcat中
  • 四 HTTP协议
    • 4.1 使用抓包来查看http协议信息
    • 4.2 请求的执行流程
    • 4.3 http请求
    • 4.4 Http响应
  • 五 Servlet
    • 5.1 Servlet介绍
    • 5.2 服务器编译环境设置
    • 5.3 Servlet的入门
      • 5.3.1 入门案例
      • 5.3.2 执行流程
      • 5.3.3 注意事项
    • 5.4 Servlet详解
      • 5.4.1 Servlet处理请求
      • 5.4.2 创建Servlet的三种方式
    • 5.5 Servlet生命周期
    • 5.6 load-on-startup配置
    • 5.7 Servlet配置
      • 5.7.1 自定义Servlet
      • 5.7.2 < url-parttern >书写规则
    • 5.8 缺省Servlet
    • 5.9 服务器中路径
    • 5.10 ServletConfig对象
    • 5.11 ServletContext对象
      • 5.11.1 介绍
      • 5.11.2 ServletContext对象作用
    • 5.12 ServletContext综合案例
    • 5.13 Servlet3.0
  • 六 request与response对象
    • 6.1 介绍
    • 6.2 response对象操作响应行、响应头
    • 6.3 response操作重定向
    • 6.4 response操作定时跳转
    • 6.5 response操作响应正文
    • 6.6 request操作请求行
    • 6.7 request操作请求头
    • 6.8 request操作请求参数
    • 6.9 请求参数中文乱码
      • 6.9.1 post
      • 6.9.2 get
      • 6.9.3 终极解决方案
    • 6.10 request操作请求转发
    • 6.11 请求转发和重定向
    • 6.12 request作为域对象
  • 七 会话技术
  • 八 Cookie
    • 8.1 Cookie介绍
    • 8.2 Cookie的基本使用
    • 8.3 Cookie的相关设置
    • 8.4 Cookie案例
      • 8.4.1 记录上一次访问时间
      • 8.4.2 商品浏览记录
    • 8.5 CookieUtils工具类
  • 九 Session
    • 9.1 Session基本使用
    • 9.2 Session相关配置
    • 9.3 session的基本使用
    • 9.4 session和request的区别
    • 9.5 session和cookie的区别
    • 9.6 session案例
      • 9.6.1 登录
      • 9.6.2 随机验证码
  • 十 过滤器
    • 10.1 过滤器的概念
    • 10.2 过滤器的基本使用
    • 10.3 过滤器的相关配置
    • 10.4 过滤器的注解开发
    • 10.5 过滤器案例
      • 10.5.1 中文乱码
      • 10.5.2 自动登录
      • 10.5.3 敏感词屏蔽
  • 十一 监听器
    • 11.1 监听器的介绍
    • 11.2 监听器的分类
      • 11.2.1 一类监听器
      • 11.2.2 二类监听器
      • 11.2.3 三类监听器
    • 11.3 监听器注解开发
    • 11.4 监听器综合案例
      • 11.4.1 记录登录人数
  • 十二 JavaWeb综合案例
    • 12.1 用户管理与DML操作
      • 12.1.1 用户列表
      • 12.1.2 删除用户
      • 12.1.3 批量删除
      • 12.1.4 添加用户
      • 12.1.5 修改用户
    • 12.2 BaseServlet优化案例
      • 12.2.1 BaseServlet 的作用
      • 12.2.2 实现原理
      • 12.2.3 BaseServlet的应用
      • 12.2.4 BaseServlet的优化
    • 12.3 jsp优化登录案例
    • 12.4 三层结构优化
      • 12.4.1 准备工作
      • 12.4.2 登录
      • 12.4.3 注销登录
      • 12.4.4 用户列表
      • 12.4.5 登录校验
      • 12.4.6 删除用户
      • 12.4.7 修改用户
  • 十三 分页查询
    • 13.1 数据库的物理分页
    • 13.2 分页查询流程分析
    • 13.3 分页代码实现
      • 13.3.1 后台代码
      • 13.3.2 前端代码
    • 13.4 另一版本
  • 十四 文件上传
    • 14.1 概念及原理
    • 14.2 页面实现
    • 14.3 编写服务器程序
      • 14.3.1 文件上传
      • 13.3.2 文件下载
      • 13.3.3 多文件上传
  • 十五 BaseServlet

一 web引言

1.1 生活中的上网方式

两种方式:可以通过浏览器(browser)进行上网,也可以通过客户端(client)进行上网

两种结构
BS结构 browser server 浏览器服务器
CS结构 client server 客户端服务器

BS结构 browser server 浏览器服务器
- 不需要安装客户端,只要能连上网,就能随时随地使用
- 开发人员只需要对服务器端程序进行开发、维护,降低开发维护难度和开发维护成本
- 浏览器主要负责用户界面的动态展示,只处理一些简单的逻辑功能
- 所有具体业务逻辑的处理都由服务器端程序完成,所以程序负载几乎都转移给服务器
端。
- 但是随着服务器负载的增加,可以平滑地增加服务器的个数并建立集群服务器系统,然
后在各个服务器之间做负载均衡。
CS结构 client server 客户端服务器
- 将应用程序分为客户端和服务器端两层,客户端程序用于展示功能,为用户提供操作界
面,同时也可以进行业务逻辑的处理;而服务器端程序负责操作数据库完成数据处理等
核心业务
- 由此可见通过C/S开发模型开发的应用程序,客户端程序可以承担一部分业务逻辑处
理,特别是数据的预处理工作,减轻了服务器端程序的压力
BS优缺点:
优点:实时地更新数据(新功能的增加只需要在服务端完成, 浏览器刷新就好了),
缺点:将负载给了服务器CS优缺点:
优点:客户端也分担了一部分负载,
缺点:如果有新的功能要增加必须要重新下载客户端

------------------------------

1.2 Web服务器

作用:能够让本地电脑中的资源可以被其他的电脑访问

常见的javaweb服务器weblogic它是oracle公司的,已经被oracle收购,它是全面支持javaee规范,收费的大型的web服务器,它是企业中主流的服务器,在网络上学习资料比较多。websphere它是ibm公司的一个大型的收费的全面支持javaee规范的javaee容器。tomcat它是开源的免费的servlet规范的服务器。 它是apache一个web服务器。jbosshibernate公司产品,不是开源免费的,是javaee规范的容器。ngixNginx ("engine x") 是一个高性能的 HTTP 和 反向代理服务器

------------------------------

1.3 Web相关概念

什么是web?
Web指的就是网页,我们所说的web指的是internet主机(服务器)上的供外界访问的资源
web资源可以分为两种:静态web资源、动态web资源

静态web资源
指web页面上供人们浏览的数据,它们始终不变。例如html优点:
静态网站开发简易,只需要掌握HTML、CSS和JS就可以开发
静态访问速度快,因为静态网页不需要和任何程序进行交互,更不需要对数据进行处理缺点:
静态网站内容无法实时更新,因为网站由一个个的静态HTML网页构成,新增内容只能
通过开发人员修改代码
网站内容过多时,每个页面都需要单独制作,需要不断编写和维护HTML页面,增加了
网站开发人员的工作量,提高了运营费用。
动态web资源
指web页面中内容是由程序产生的,供人们浏览,并且在不同的时间点,数据不一样,并且
还可以实现人与人之间的交互。用到Servlet和JS等技术.优点
维护方便、可以根据用户需求实现各种功能
查询信息方便,能存储大量数据,需要时能立即查询
网站内容可以实时动态更新
与用户交互性强,提高用户粘性缺点
技术要求高

二 Tomcat

2.1 Tomcat安装与配置

  • 测试是否安装成功:
    在tomcat的安装目录下有一个bin目录 ,在目录 中有一个startup.bat文件执行它。打开浏览器,在浏览器的地址栏上输入 http://localhost:8080

  • 配置

    • JAVA_HOME配置
      在tomcat的安装目录bin文件夹下的catalina.bat中使用了JAVA_HOME,所以,安装
      tomcat必须要求系统配置中有JAVA_HOME,如果没有配置,执行startup.bat文件时会出现闪退效果
    • 端口号配置
      tomcat默认使用的8080端口,可以进行端口号的修改,修改tomcat的端口号,在
      tomcat/conf/server.xml文件, 可以添加80端口,80是http协议默认的端口。

三 Web项目

3.1Web项目分类

 - Web静态项目包含都是静态资源:html、js、css、图片、音频等等- Web动态项目: 不是必须包含动态资源包含都是静态资源:html、js、css、图片、音频等等
​       那么和静态项目的区别在哪里?可以有动态资源及WEB-INF文件夹
​       通过http://localhost:8080/    访问的资源是来自于tomcat服务器的动态web项目(内置),
​       而在tomcat的一个安装目录中,是由一个webapps的文件夹专门用来部署web项目

------------------------------

3.2 tomcat部署项目

  • 方式一:直接将web应用程序放置到webapps目录
    直接将一个web应用程序放置在tomcat/webapps目录下。这时web应用程序目录名称就是我们访问tomcat下的这个应用程序的名称

  • 方式二:虚拟目录初级版
    将一个不在tomcat下的web应用程序部署加载。可以在tomcat/conf/server.xml文件中配置,在server.xml文件中的标签中添加一段配置

<Context docBase="磁盘路径" path="/hello" />
 经过以上配置后,在浏览器上可以输入http://localhost/hello来访问但是,在tomcat6以后已经不建议使用了。
  • 方式三:虚拟目录优化版
    在tomcat/conf/Catalina/localhost下创建任意名称的一个xml文件,例如创建一个good.xml文件,在good.xml中书写
<Context docBase="磁盘路径" />
 这种方案配置,xml文件的名称就是访问路径,在浏览器中访问http://localhost/good

------------------------------

3.3 IDEA配置Tomcat

  • 1 选择Edit Configurations
  • 2 点击加号 ->tomcat server -> local
  • 3 点击Configure -> 点击加号 -> 选择tomcat

------------------------------

3.4 idea中的web项目的内容部署到tomcat中

只有资源来到了day50_war_exploded文件夹中,才意味着部署成功

src文件夹:
​       可以部署上去!部署到了项目中的\WEB-INF\classes文件夹中​web文件夹:
​       可以部署上去!部署到了项目目录中!​day50项目下:
​       不可以部署上去

四 HTTP协议

协议:两个设备进行数据交换的约定!
Http协议:超文本传输协议(hypertext transfer protocl)
超文本:字符、音频、视频、图片等等
基于tcp协议。tomcat服务器底层实现本质上就是TCP(Socket)

4.1 使用抓包来查看http协议信息

经过演示发现,浏览器和服务器,它们之间进行交互,是一个请求-响应模型!!!请求:
​   请求行
​   请求头
​   请求正文响应:
​   响应行
​   响应头
​   响应正文
通过抓包可以看到如下信息General:请求行,响应行Request Headers:请求头Response Headers:响应头响应正文:将显示内容携带到浏览器请求正文:用来接收请求的参数.

------------------------------

4.2 请求的执行流程

  • 发起请求
  • 域名解析
    本地域名解析器(C:\Windows\System32\drivers\etc\host),
    ​ 如果本地解析器无法解析,那么就交给互联网上的DNS解析器
    ​ 得到IP
  • 根据ip和端口,可以得到一个Socket对象,执行请求
    携带请求行、请求头、请求正文
  • 服务器响应浏览器
    携带响应行、响应头、响应正文

------------------------------

4.3 http请求

请求组成:请求行、请求头、请求正文

  • 请求行
Request URL : 请求路径,告诉服务器要请求的资源路径
​Request Method : 请求方式 , GET/POST
​protocol : http协议版本

---------------

  • GET请求和POST请求
get请求只能携带小数据、get请求下的请求参数会直接拼接到Request URL(请求网址)后面,QueryStringParameters​post请求可以携带大数据、post请求下的请求参数会存放到请求正文​   请求参数:比如,表单中的输入框中的值.​  如果我们要做文件上传,需要用到post请求,文件比较大

---------------

  • 请求头
Content-Type:浏览器告诉服务器,请求正文的数据类型
​User-Agent:浏览器告诉服务器,我是个什么样的浏览器

---------------

  • 请求正文
请求正文,只有当请求方式为post,且有请求参数时才会有请求正文

------------------------------

4.4 Http响应

Http响应组成:响应行、响应头、响应正文

  • 响应行
Status Code : 响应状态码​ 常见的有:
​       200:服务器响应成功
​       302: 告诉浏览器,进行重定向
​       304: 页面上的内容没有发生改变,不需要重新请求服务器
​       404: 没有对应的服务器资源
​       500:服务器内部错误!

---------------

  • 响应头
Location:告诉浏览器重定向的资源路径,需要结合响应状态码302使用​Content-Type:服务器告诉浏览器,响应正文的数据类型
​       Content-Type:text/html;charset=utf-8; 服务器告诉浏览器,响应正文是文本和html标签;告诉浏览器,应该以utf-8的形式进行解码!浏览器就会以html标签及utf-8的形式对响应正文进行渲染显示!!!​refresh:定时跳转​Content-Disposition:文件下载

---------------

  • 响应正文
浏览器显示的内容

五 Servlet

5.1 Servlet介绍

Servlet是运算在服务器上的一个java程序,简单说,它就是一个java类。我们要使用servlet,需要导入servlet的api.

------------------------------

5.2 服务器编译环境设置




------------------------------

5.3 Servlet的入门

5.3.1 入门案例

package servlet;

//1,自定义类继承HttpServlet
public class Demo01Servlet extends HttpServlet {//2,重写doGet和doPost方法//doGet:处理get请求//doPost:处理post请求//在doGet方法中调用doPost方法,不管是 get请求 or post请求,都交给doGet方法处理@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//处理get请求System.out.println("Demo01Servlet doGet");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//处理post请求doGet(req, resp);}
}

web/WEB-INF/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"><!--3,配置Servlet--><!--3.1,声明Servlet--><servlet><!--servlet的名称--><servlet-name>Demo01Servlet</servlet-name><!--servlet的全类名--><servlet-class>com.qfedu.servlet.Demo01Servlet</servlet-class></servlet><!--3.2,给Servlet设置访问名称Servlet should have a mapping--><servlet-mapping><!--servlet的名称--><servlet-name>Demo01Servlet</servlet-name><!--servlet的访问名称--><url-pattern>/demo01</url-pattern></servlet-mapping>
</web-app>
5.3.2 执行流程
浏览器发起请求: http://localhost:8080/day50/demo01
​   就会在服务器中找访问名称为demo01的Servlet -> Demo01Servlet
​   请求的处理就交给了Demo01Servlet的实例,根据请求方式get/post,决定是给doGet还是doPost方法处理
5.3.3 注意事项
不管是get请求还是post请求,对于服务器来说,没差别​get请求将请求参数放到请求网址​post请求将请求参数放到请求正文​服务器最终无非就要获取请求参数。getParameter()方法

------------------------------

5.4 Servlet详解

HttpServlet继承于GenericServlet、GenericServlet实现于Servlet,也就是说Servlet是顶层接口

5.4.1 Servlet处理请求
  • Servlet接口下有一个实现类叫GenericServlet,GenericServlet有一个子类HttpServlet.
  • 在Servlet接口中定义了一个方法service,它的主要作用是处理来自浏览器的请求操作。在service方法的重载的方法中,对请求方式进行判断,如果是GET就会调用doGet方法,如果是POST就会调用doPost方法。
5.4.2 创建Servlet的三种方式
  • 方式一:实现Servlet接口
在servlet接口中,没有doGet和doPost方法,处理请求是service方法(抽象的)
  • 方式二:继承GenericServlet类
在GenericServlet类中,没有doGet和doPost方法,处理请求是service方法(抽象的)
  • 方式三:继承HttpServlet类
HttpServlet类中重写service方法。​根据源码,发现重写service方法中,有将ServletRequest强转为HttpServletRequest,
​   将ServletResponse强转为HttpServletResponse
​   以上强转是因为,ServletRequest和ServletResponse并没有针对Http协议做优化!!!无法专门针对http协议调用方法!!​  HttpServletRequest和HttpServletResponse有针对http协议做优化!!!

在开发中,一般应用比较多的是使用extends HttpServlet,优点是它是与http协议相关
的,封装了http协议相关的操作。

------------------------------

5.5 Servlet生命周期

在javax.servlet.Servlet接口中定义了三个方法init service destroy它们就是servlet的生命周期
方法

public interface Servlet {//监听Servlet的初始化void init(ServletConfig var1) throws ServletException;ServletConfig getServletConfig();//处理请求void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;String getServletInfo();//监听Servlet的销毁void destroy();
}
  • 调用构造方法创建Sevlet对象(Servlet是单例的,构造方法只执行一次)
  • 调用init方法,进行初始化操作(只执行一次)
  • 当有请求访问Servlet时,会执行service方法(每次请求都执行),在父类HttpServlet中,重写service方法,会把请求分发给doPost()和doGet()方法
  • 当容器关闭时,会执行destroy方法,销毁对象,释放资源

------------------------------

5.6 load-on-startup配置

根据Servlet生命周期,可知,servlet默认不会随着服务器的启动而初始化load on startup可以让servlet随着服务器的启动而初始化对于load-on-startup它的可以配置的值有10个,1代表优先级最高,数值越大,优先级越低

------------------------------

5.7 Servlet配置

5.7.1 自定义Servlet

对于servlet,我们需要在web.xml文件中对其进行配置

  • 在web.xml中声明Servlet
<servlet><servlet-name>Demo01Servlet</servlet-name><servlet-class>servlet.Demo01Servlet</servlet-class></servlet>

---------------

  • 在web.xml中给Servlet映射访问路径
<servlet-mapping><servlet-name>Demo01Servlet</servlet-name><url-pattern>/demo01</url-pattern></servlet-mapping>
一个<servlet>可有多个<servlet-mapping>与其对应
5.7.2 < url-parttern >书写规则
  • 完全匹配
要求网址上的访问名称完全和<url-parttern>一致​必须以"/"开头,否则会报错:IllegalArgumentException : Invalid <url-pattern>

---------------

  • 目录匹配
要求网址上的访问名称中的目录和<url-parttern>一致​必须以"/"开头,以"*"结尾​比如:/a/b/* , 目录必须是/a/b,后面随便写

---------------

  • 后缀名匹配
要求网址上的访问名称中的后缀和<url-parttern>一致​不能以"/"开头,以"*"开头,后缀名根据业务写​比如:*.xyz。后缀名必须是xyz,其他随意写!!!

------------------------------

5.8 缺省Servlet

创建一个servlet时,如果它的url-pattern的配置值为”/”这时这个servlet就是一个缺省的
servlet,tomcat服务器中默认就有缺省Servlet

  • 缺省Servlet的作用
凡是在web.xml文件总找不到匹配的<servlet-mapping>元素的URL,它们的请求都将交给
缺省Servlet处理。也就是说,缺省的servlet用于处理其他Servlet处理不了的请求当访问tomcat服务中的静态资源(html、图片等等)时,实际上是在访问这个缺省的servlet
  • 自定义缺省Servlet
在当前工程中自定义Servlet,将url-parttern设置为"/",就覆盖了tomcat容器中的缺省Servlet
  • 应用
 SpringMVC框架中,用于放行静态资源

------------------------------

5.9 服务器中路径

  • 带协议的绝对路径
http://localhost:8080/day51/img/girl.jpg
  • 不带协议的绝对路径
/day51/img/girl.jpg
  • 相对路径
当前目录:./ ,可以省略上一级目录:../

------------------------------

5.10 ServletConfig对象

ServletConfig是javax.servlet.包下的一个接口。ServletConfig它是Servlet的一个配置对象

ServletConfig对象是由服务器创建的,它是通过Servlet的init方法传递到Servlet中

  • 作用
获取Servlet名称 getServletName获取Servlet初始化参数 getInitParameter getInitParameterNames获取ServletContext对象getInitParameter(String parameterName):根据参数名称获取指定的参数值getInitParameterNames():获取所有的参数名称获取域对象:ServletContext
public class Demo11Servlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletConfig servletConfig = getServletConfig();String servletName = servletConfig.getServletName();System.out.println(servletName+"正在运行...");System.out.println("--------------------");String username = servletConfig.getInitParameter("username");System.out.println(username);String password = servletConfig.getInitParameter("password");System.out.println("--------------------");Enumeration<String> parameterNames = servletConfig.getInitParameterNames();while (parameterNames.hasMoreElements()){String parameterName = parameterNames.nextElement();String parameterValue = servletConfig.getInitParameter(parameterName);System.out.println("name"+parameterName+"password"+parameterValue);}ServletContext servletContext = getServletContext();}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req,resp);}
}
<servlet><servlet-name>Demo11Servlet</servlet-name><servlet-class>servlet.Demo11Servlet</servlet-class><init-param><param-name>username</param-name><param-value>root</param-value></init-param><init-param><param-name>password</param-name><param-value>root123</param-value></init-param></servlet><servlet-mapping><servlet-name>Demo11Servlet</servlet-name><url-pattern>/demo11</url-pattern></servlet-mapping>

------------------------------

5.11 ServletContext对象

相当于是整个应用程序对象

5.11.1 介绍
  • ServletContext它是javax.servlet包下的一个接口
  • 当服务器启动时,会为服务器中的每一个web应用程序创建一个ServletContext对象,一个ServletContext对象对应的就是一个web应用程序
  • 对于ServletContext,我们叫它上下文对象,ServletConfig对象中维护了ServletContext对象,也就是说,我们可以通过ServletConfig对象来获取ServletContext对象
  • 在web应用中的servlet要想实现资源的共享,可以通过ServletContext来完成,
    ServletContext也叫做域对象
5.11.2 ServletContext对象作用
  • 实现Servlet资源共享

ServletContext是一个域对象,可以用来存储数据.可以将它想像成一个Map<String,Object>,可以通过它实现Servlet资源共享

在应用程序中的任何位置都能够访问* getAttribute(String parameterName) : 获取ServletContext域中指定名称的参数值* setAttribute(String paramterName,Object parameterValue):存储参数到ServletContext域中* removeAttribute(String parameterNam):将ServletContext域中指定名称的参数移除

---------------

  • 获取全局初始化参数

在web.xml中配置的全局初始化参数,可以通过ServletContext对象获取

public class Demo15Servlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext servletContext = getServletContext();Enumeration<String> parameterNames = servletContext.getInitParameterNames();while (parameterNames.hasMoreElements()){String parameterName = parameterNames.nextElement();String parameterValue = servletContext.getInitParameter(parameterName);System.out.println("name:"+parameterName+"value:"+parameterValue);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}
<context-param><param-name>username</param-name><param-value>root</param-value></context-param><servlet><servlet-name>Demo15Servlet</servlet-name><servlet-class>servlet.Demo15Servlet</servlet-class></servlet><servlet-mapping><servlet-name>Demo15Servlet</servlet-name><url-pattern>/demo15</url-pattern></servlet-mapping>

---------------

  • 获取资源在服务器上的真实磁盘路径

getRealPath:依据当前项目去生成真实磁盘路径

servletContext.getRealPath("upload"):当前项目的服务器磁盘路径/uploadservletContext.getRealPath("upload/img"):当前项目的服务器磁盘路径/upload/img
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext servletContext = getServletContext();String upload = servletContext.getRealPath("upload");System.out.println(upload);}

------------------------------

5.12 ServletContext综合案例

  • 需求:统计站点访问次数
public class Demo17Servlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1 获取ServletContext对象ServletContext servletContext = getServletContext();//2 判断是否第一次Integer count = (Integer) servletContext.getAttribute("count");if (count == null) {//2.1 第一次访问count = 1;System.out.println(count);servletContext.setAttribute("count", count);} else {//2.2 非第一次访问count++;System.out.println(count);servletContext.setAttribute("count", count);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

------------------------------

5.13 Servlet3.0

支持注解开发,由注解配置来代替web.xml配置

  • 在Servlet类上直接使用@WebServlet注解
@WebServlet(name = "Demo01Servlet", urlPatterns = {"/demo01", "/mydemo01"},initParams = {@WebInitParam(name = "username", value = "root"),@WebInitParam(name = "password", value = "123456")})

---------------

  • 常用属性
name:String:设置Servlet名称urlPatterns:String[]:设置Servlet的访问路径loadOnStartup:int:设置Servlet的load-on-startup属性initParams:WebInitParam[]:设置Servlet的初始化参数

六 request与response对象

6.1 介绍

当浏览器发起请求后,服务器会创建一个请求对象、一个响应对象,通过service方法传入给Serlvet

request与response的作用* request对象就可以操作http请求信息* response对象就可以操作http响应信息
ServletRequest与HttpServletRequest及ServletResponse与HttpServletResponse关系* ServletRequest与ServletResponse它们是HttpServletRequest与HttpServletResponse的
父接口

------------------------------

6.2 response对象操作响应行、响应头

操作响应行* setStatus(int status):操作正常响应状态码,比如:200、302* ssendError(int status):操作错误响应状态码,比如: 404
操作响应头* public void addHeader(String name, String value):直接覆盖响应头原有值* public void setHeader(String name, String value):在响应头原有值的后面追加

------------------------------

6.3 response操作重定向

通过各种方法将各种网络请求重新定个方向转到其它位置
通过操作状态码302及响应头location来实现

重定向的流程* 当浏览器访问一个资源Demo03Servlet,访问名称为“/demo03”* Demo03Servlet进行重定向* 操作响应状态码302* 操作响应头Location,服务器告诉浏览器,重定向的资源的访问路径* 浏览器进行一个新的请求,完成重定向
  • 方式一
  response.setStatus(302);response.setHeader("Location","demo04");

---------------

  • 方式二
response.sendRedirect("demo04");

------------------------------

6.4 response操作定时跳转

一个资源定时一段时间之后,跳转到另外一个资源
操作响应头refresh

resp.setHeader("refresh","5;url=demo07");

------------------------------

6.5 response操作响应正文

响应正文:就是浏览器显示的主体内容

response.getWriter().write():操作响应正文

响应正文中文乱码* 本质原因,服务器的编码和浏览器的解码,格式不同!* setCharacterEncoding("utf-8"):* 告诉服务器,应该以utf-8格式编码响应正文* setHeader("Content-Type","text/html;charset=utf-8"):* 告诉浏览器 , 响应正文是文本+html标签,应该以utf-8格式解码响应正文* setContentType("text/html;charset=utf-8")* 告诉服务器,应该以utf-8格式编码响应正文* 告诉浏览器 , 响应正文是文本+html标签,应该以utf-8格式解码响应正文
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//告诉服务器,编码格式为utf-8
//        response.setCharacterEncoding("utf-8");//单单只告诉服务器的编码格式,不合适的!浏览器的编码格式不确定!//告诉浏览器,编码格式也应该是utf-8
//        response.setHeader("Content-Type","text/html;charset=utf-8");response.setContentType("text/html;charset=utf-8");String msg1 = "hello world 老邱";PrintWriter writer = response.getWriter();//操作响应正文writer.write(msg1);//操作响应正文中文乱码//不仅要告诉服务器编码格式,还要告诉浏览器编码格式! 它们应该是统一的!//有没有一个简单,就是既告诉服务器的编码,同时也告诉浏览器的编码
}

------------------------------

6.6 request操作请求行

getRequestURI    获取请求路径getMethod 获取请求方式getRemoteAddr 获取请求ipgetLocalPort  获取请求端口getQueryString    请求网址"?"后面的路径
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Demo02Servlet");//获取请求路径String requestURI = request.getRequestURI();System.out.println(requestURI);//获取请求方式String method = request.getMethod();System.out.println(method);//获取请求ipString remoteAddr = request.getRemoteAddr();System.out.println(remoteAddr);//获取请求端口int port = request.getLocalPort();System.out.println(port);//获取请求网址后的请求参数String queryString = request.getQueryString();//在网址后的请求参数,如果要使用,需要做字符串的拆分!!System.out.println(queryString);//SpringMVC:前后端交互使用的是json字符串,json解析 --> java对象!!}

------------------------------

6.7 request操作请求头

getHeader()  获取指定请求头的值
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Demo03Servlet");//获取User-Agent请求头:判定请求是由哪种浏览器发起String userAgent = request.getHeader("User-Agent");System.out.println(userAgent);}

------------------------------

6.8 request操作请求参数

请求正文:post+请求参数
请求参数:不管是get请求 还是 post请求

getParameter 获取指定请求参数值getParameterNames  获取所有请求参数名称getParameterValues(String parameterName)  获取指定请求参数所有值getParameterMap  键,获取所有请求参数名称 , 相当于getParameterNames方法值,获取指定请求参数所有值,相当于getParameterValues方法getParameter 能拿到表单中的参数、URL中的参数
getAttribute    拿的是通过setAttribute存入request的属性
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取指定参数值String username = request.getParameter("username");String password = request.getParameter("password");System.out.println("username : " + username + " , password : " + password);System.out.println("---------------");//获取所有请求参数名称Enumeration<String> parameterNames = request.getParameterNames();while (parameterNames.hasMoreElements()) {String parameterName = parameterNames.nextElement();String parameterValue = request.getParameter(parameterName);System.out.println("name : " + parameterName + " , value : " + parameterValue);}System.out.println("---------------");//获取指定请求参数所有值String[] usernames = request.getParameterValues("username");System.out.println(usernames[0]);String[] hobbys = request.getParameterValues("hobbys");for (String hobby : hobbys) {System.out.println(hobby);}System.out.println("---------------");//获取请求参数对应的map ://getParameterMap() -> Map(String,String[])//键:请求参数名称  相当于 getParameterNames//值:一组请求参数值 相当于 getParameterValuesMap<String, String[]> parameterMap = request.getParameterMap();//双列集合:获取到所有的实体对象(键值对象)Set<Map.Entry<String, String[]>> entrySet = parameterMap.entrySet();for (Map.Entry<String, String[]> entry : entrySet) {//键 - 请求参数名称String parameterName = entry.getKey();//值 - 一组请求参数值String[] values = entry.getValue();StringBuffer valueStr = new StringBuffer();for (String value : values) {valueStr.append(value + " ");}System.out.println("参数名称 : "+ parameterName + " , 参数值 : " + valueStr);}}

------------------------------

6.9 请求参数中文乱码

6.9.1 post

本质:请求正文中的中文参数乱码

解决方案* request.setCharacterEncoding("utf-8")* 告诉服务器应该以utf-8解码请求正文* 逆向,先编码在解码* 先将乱码字符串以iso8859-1编码成字节* 将字节以utf-8解码成字符串
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//不管是get请求 还是 post请求,都存在请求参数中文乱码问题//post请求 告诉服务器,应该以utf-8来解码请求正文request.setCharacterEncoding("utf-8");String username = request.getParameter("username");username = new String(username.getBytes("iso8859-1"),"utf-8");System.out.println(username);String password = request.getParameter("password");System.out.println(password);

将tomcat容器的URIEncoding=“utf-8”,对Query String中的请求参数有效,对请求正文中无效,对post请求下的中文乱码无效

---------------

6.9.2 get

本质:Query String中的中文参数乱码

解决方案* 逆向,先编码在解码* 先将乱码字符串以iso8859-1编码成字节* 将字节以utf-8解码成字符串
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//不管是get请求 还是 post请求,都存在请求参数中文乱码问题//告诉服务器,应该以utf-8对请求正文进行解码//get请求中,有请求正文么? 没有!
//        request.setCharacterEncoding("utf-8");String username = request.getParameter("username");//将乱码的字符串编码(iso8859-1)成字节
//        byte[] bytes = username.getBytes("iso8859-1");//将字节解码(utf-8)成字符串
//        String newUsername = new String(bytes,"utf-8");username = new String(username.getBytes("iso8859-1"),"utf-8");System.out.println(username);String password = request.getParameter("password");System.out.println(password);}

修改tomcat容器的URIEncoding=“utf-8”

<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"URIEncoding="utf-8"redirectPort="8443" />

request.setCharacterEncoding(“utf-8”)对get请求无效,告诉服务器应该以utf-8来解码请求正文,跟Query String 没有关系

---------------

6.9.3 终极解决方案
方案* tomcat8.5 * 相当于是tomcat7.0修改了URIEncoding="utf-8"* 就解决了get请求参数中文乱码问题*  request.setCharacterEncoding("utf-8")* 就解决了post请求参数中文乱码问题
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");String username = request.getParameter("username");System.out.println(username);String password = request.getParameter("password");System.out.println(password);}

------------------------------

6.10 request操作请求转发

  • .request的生命周期

    • Request对象是在浏览器向服务器发送请求时,服务器会创建request对象,当服务器产生了响应时,request对象就销毁。简单说就是请求时创建request,响应时销毁request。
  • 请求转发
    • 请求转发指的就是服务器内的资源的跳转,请求转发时,就会形成一个请求链,它们共享同一个request与response对象。
  • 请求转发的实现
    • request.getRequestDispathcher(“路径”).forward(request,response);
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Demo08Servlet");//转发到Demo09Servlet , 重定向 : 操作响应状态码302,操作响应头location  都是通过response//获取一个转发器对象,传入一个转发地址RequestDispatcher dispatcher = request.getRequestDispatcher("demo09");//开始转发dispatcher.forward(request,response);}

转发只有一次请求

------------------------------

6.11 请求转发和重定向

转发forward:服务器内部进行,客户端不知道。转发可以共享request中的数据。转发只能在当前工程内部进行。
重定向:redirect:由服务器返回给客户端地址,再由客户端发起第二次请求。重定向不能共享request中的数据。重定向可以访问其他工程。
请求次数* 重定向有2次请求* 转发有1次请求跳转区别* 重定向既可以站内资源进行跳转,站外资源也可以进行跳转* 转发只能站内资源进行跳转路径区别* 要转发的资源的相对路径无区别* 要转发的资源的绝对路径有区别* 重定向,是从先从项目开始找,再找资源* 转发,是直接从项目中找资源

不能重定向两次

重定向不能拿到上一个请求中的参数,但是可以在重定向的url中拼接参数

/*** 重定向和转发的区别之站内资源、站外资源*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//重定向到站外资源response.sendRedirect("http://www.baidu.com/");//转发到站外资源request.getRequestDispatcher("http://www.baidu.com/").forward(request,response);}
/*** 重定向和转发的区别之路径*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//重定向和转发,使用相对路径是没有区别的!//使用重定向跳转到index.html(相对路径)response.sendRedirect("index.html");//使用转发跳转到index.html(相对路径)request.getRequestDispatcher("index.html").forward(request,response);//使用重定向跳转到index.html(绝对路径)response.sendRedirect("/day55/index.html");//使用转发跳转到index.html(绝对路径)request.getRequestDispatcher("/index.html").forward(request,response);}

------------------------------

6.12 request作为域对象

域对象:可以存储数据的对象

ServletContext域对象的作用范围:不同设备、当前项目中的任意一个资源都可以访问ServletContext域中的数据

request域对象的作用范围* request对象的生命周期* 发起请求时,request初始化* 响应时,request销毁* request域对象的作用范围在一次请求中!request在重定向和转发中使用!* 重定向中不能使用request域对象* 转发中可以使用request域对象
/*** request域对象在重定向和转发中的使用*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//request域操作数据的方法和ServletContext域是一样!//setAttribute、getAttribute、removeAttribute//往request域中存储一个变量String msg = "hello servlet";request.setAttribute("msg",msg);//重定向到Demo13Servlet  request.getContextPath() 获取项目名称response.sendRedirect(request.getContextPath()+"/demo13");request.getRequestDispatcher("/demo13").forward(request,response);}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.removeAttribute("msg");System.out.println("Demo13Servlet");String msg = (String) request.getAttribute("msg");System.out.println(msg);}

七 会话技术

打开浏览器,访问服务器中资源,关闭浏览器;这个过程就是会话

  • 分类
  * Cookie会话技术;浏览器会话技术* Session会话技术;服务器会话技术
  • 作用
解决ServletContext域对象、Request域对象存储数据所存在的问题


八 Cookie

8.1 Cookie介绍

网景公司发明。是浏览器的会话技术

  • Cookie的流程
  * 浏览器请求服务器,请求Demo01Servlet,创建一个Cookie对象,名称为cookie1* 可以通过响应头Set-Cookie,携带cookie给浏览器进行保存* 浏览器再次请求服务器,请求Demo02Servlet,获取cookie1对象

------------------------------

8.2 Cookie的基本使用

  • 设置Cookie
//方式一(不推荐)
response.addHeader("set-cookie","msg=hellocoolie");
//方式二
Cookie cookie = new Cookie("msg","hellocookie");
response.addCookie(cookie);
  • 获取Cookie
开发步骤* 通过request对象获取所有的Cookie对象,存储到一个数组中* 遍历该数组,匹配Cookie名称* 如果匹配上,就知道了指定的Cookie对象* 如果匹配不上,就没有指定的Cookie对象
Cookie[] cookies = request.getCookies();
Cookie cookie = null;
for(Cookie sonCookie : cookies){if("msg".equals(sonCookie.getName())){cookie = sonCookie;}
}
if(null != cookie){System.out.println("name : "+msgCookie.getName() + " , value : "+ msgCookie.getValue());
}

------------------------------

8.3 Cookie的相关设置

  • 持久化设置
cookie的生命周期* 默认是随着浏览器的关闭而销毁setMaxAge* 设置cookie的存活时长,cookie就可以不随着会话的关闭而销毁* 取值有三种:>0有效期,单位秒;=0浏览器关闭;<0内存存储,默认-1
  • 路径设置
默认情况下,Cookie对象会随着任何一个请求携带到服务器setPath  设置Cookie的访问路径
 Cookie cookie = new Cookie("msg","helloworld");cookie.setPath("/day56/demo04");response.addCookie(cookie);

cookie对象只有访问路径包含"/day56/demo04",才会跟随请求携带到服务器

------------------------------

8.4 Cookie案例

8.4.1 记录上一次访问时间
需求:第一次访问,就直接打印当前时间不是第一次访问,就打印上一次的访问时间开发步骤:获取对应的Cookie对象判断是否是第一次访问如果是第一次访问打印当前时间将当前时间存储到Cookie中如果不是第一次访问打印上一次访问时间将当前时间存储到Cookie中
  //判断是否是一次请求Cookie[] cookies = request.getCookies();Cookie cookie = null;//记录上一次的访问时间if (cookies != null && cookies.length != 0 ) {for (Cookie sonCookie : cookies) {if ("lastTime".equals(sonCookie.getName())) {cookie = sonCookie;}}}SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");if (null == cookie) {//第一次访问 ,打印当前时间,并将创建Cookie对象,存储当前时间Date currentDate = new Date();System.out.println("第一次访问,时间为" + format.format(currentDate));cookie = new Cookie("lastTime",currentDate.getTime()+"");} else {//不是第一次访问,从cookie取出上一次的访问时间,并打印。获取当前时间,并存储cookie对象中long lastDateMills = Long.parseLong(cookie.getValue());Date lastDate = new Date(lastDateMills);//获取到了上一次的访问时间String lastTimeStr = format.format(lastDate);System.out.println("上一次访问,时间为" + lastTimeStr);//获取当前时间,并存储cookie对象中Date currentDate = new Date();//            cookie.setValue(currentDate.getTime()+"");cookie = new Cookie("lastTime",currentDate.getTime()+"");}  response.addCookie(cookie);
8.4.2 商品浏览记录
需求:浏览商品,将商品的浏览的记录起来,并显示!
  <!--页面代码 books.html--><a href="/day56/history?id=0">西游记</a><br><a href="/day56/history?id=1">红楼梦</a><br><a href="/day56/history?id=2">水浒传</a><br><a href="/day56/history?id=3">三国志</a><br>
/* * 获取history的Cookie对象* * 判断商品浏览记录是否为空* * 如果浏览记录没有* * * 创建Cookie,并将当前的商品记录到Cookie中* * 如果浏览记录有* * * 有当前的商品,不做任何处理* * * 没有当前商品,就需要将当前的商品拼接到已有记录中
*/@WebServlet(name = "HistoryServlet", urlPatterns = "/history")
public class HistoryServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String id = request.getParameter("id");Cookie cookie = null;Cookie[] cookies = request.getCookies();if (null != cookies && 0 != cookies.length){for (Cookie sonCookie : cookies) {if ("history".equals(sonCookie.getName())) {cookie = sonCookie;}}}if (null == cookie) {//之前没有任何浏览记录 ,创建Cookie对象 ,并存储浏览记录(id)cookie = new Cookie("history",id);} else {//之前有一些浏览记录String historyStr = cookie.getValue();if (!historyStr.contains(id)) {//有一些记录,但是不包含当前浏览的商品;//将浏览商品拼接到已有浏览记录中//120//1-2-0historyStr += "-"+id;cookie.setValue(historyStr);} else {//有一些记录,包含当前浏览的商品 ,不做任何处理}}response.addCookie(cookie);//上述代码,已经完成了商品浏览记录功能,剩下就是要显示商品浏览记录response.sendRedirect(request.getContextPath()+ File.separator+"showHistory");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
  /** 显示商品浏览记录* * 获取history对应的Cookie对象* * 获取对应的商品浏览记录* * 判断是否有浏览记录* * 如果没有,就显示“没有浏览记录”* * 如果有,就显示处理浏览记录字符串*/
@WebServlet(name = "ShowHistoryServlet", urlPatterns = "/show")
public class ShowHistoryServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Cookie cookie = null;Cookie[] cookies = request.getCookies();if (null != cookies && 0 !=  cookies.length) {for (Cookie sonCookie : cookies) {if ("history".equals(sonCookie.getName())) {cookie = sonCookie;}}}StringBuffer responseContent = new StringBuffer();//记录响应正文if (null == cookie) {//没有浏览记录responseContent.append("<font color='red'>没有浏览记录</font>,");responseContent.append("<a href='books.html'>浏览商品</a>");} else {//有浏览记录//获取浏览记录 0-1-2-3String[] bookNames = {"西游记","红楼梦","水浒传","三国志"};String historyStr = cookie.getValue();String[] historys = historyStr.split("-");responseContent.append("您的浏览记录如下:<br>");for (String history : historys) {//history : 0 / 1 / 2 /3String bookName = bookNames[Integer.parseInt(history)];responseContent.append(bookName+"<br>");}}response.setContentType("text/html;charset=utf-8");response.getWriter().write(responseContent.toString());}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

------------------------------

8.5 CookieUtils工具类

获取指定名称的Cookie对象

public class CookieUtils {public static Cookie getCookie(Cookie[] cookies,String cookisName){if(cookies!=null&&cookies.length!=0){for(Cookie sonCookie:cookies){if(cookisName.equals(sonCookie.getName())){return sonCookie;}}}return null;}
}


九 Session

9.1 Session基本使用

Cookie之所以叫做浏览器会话,原因是Cookie的数据存储到浏览器

Session之所以叫做服务器会话,原因是Session的数据存储到服务器

  • 执行流程
第一次请求Demo01Servlet时,根据request.getSession方法, 新建一个session对象
当第一次响应时,会将该session对象的id作为cookie头响应给浏览器保存set-cookie:JSESSIONID=4741C65CC84788A204E87EB870196EB0第二次请求Demo01Servlet时,根据request.getSession方法,请求中会有cookie头Cookie:JSESSIONID=4741C65CC84788A204E87EB870196EB0会根据该JSESSIONID去服务器中找有没有对应的session对象,如果有就直接用,没有就新建

------------------------------

9.2 Session相关配置

生命周期:session默认是有30分钟的存活时间,参考tomcat中的web.xml

      <session-config><session-timeout>30</session-timeout></session-config>
session和cookie是相关联的,cookie中存储了jsessionid,request.getSession方法会根据jsessionid去选择,到底是新建session对象,还是引用原来的session对象;如果,将浏览器关闭了,就意味着cookie中存储的jsessionid就会销毁,对应request.getSession就会新建一个session对象,但是原来的session对象还存在
session只有两种情况会销毁调用了invalidate方法过了30分钟

------------------------------

9.3 session的基本使用

setAttribute 往session域对象中存储数据getAttribute    从session域对象中获取数据removeAttribute     把session域对象中的数据移除

------------------------------

9.4 session和request的区别

request是一次请求,session是一次会话,一次会话中包含多次请求request中的数据(setAttritube)在重定向后失效,不同的request不能共享数据。
session中的数据无论是重定向还是转发,都能拿到。关闭浏览器失效

session默认有效期30分钟(打开浏览器,超过30分钟无操作,session失效)
重启Tomcat清空所有session

------------------------------

9.5 session和cookie的区别

session存在于服务端,可以存放任意类型的数据,依赖于cookie中的JSESSIONID
cookie存在于客户端,只能存放字符串
用户可能禁用浏览器的cookie,导致sessionid不能存储在浏览器cookie中
服务端就不能获取用户session信息
encodeRedirect方法,将用户的sessionid拼接到url后面
String url = resp.encodeRedirectURL("/admin/list");
resp.sendRedirect(url);

------------------------------

9.6 session案例

9.6.1 登录
  • UserDao
public class UserDaoImpl implements UserDao {@Overridepublic User login(User inputUser) throws SQLException {//        ComboPooledDataSource就是连接池,连接池包含很多连接对象//        连接池作用就是减少连接的创建次数!//        第一个用户,登录,创建一个连接池,创建3个连接//        第二个用户,登录,创建一个连接池,创建3个连接//        应该只让连接池创建一次!!后面复用就OK了!!QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());User existUser = queryRunner.query("select * from tb_user where username = ? and password = ?",new BeanHandler<User>(User.class),inputUser.getUsername(),inputUser.getPassword());`在这里插入代码片`  return existUser;}}
  • LoginServlet
@WebServlet(name = "LoginServlet",urlPatterns = "/login")public class LoginServlet extends HttpServlet {private UserDao userDao = new UserDaoImpl();protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String password = request.getParameter("password");User inputUser = new User();inputUser.setUsername(username);inputUser.setPassword(password);try {User existUser = userDao.login(inputUser);System.out.println(existUser);//判断登录成功if (null == existUser) {//登录失败,请求转发,跳转到登录页面request.getRequestDispatcher("/login.html").forward(request,response);} else {//登录成功,重定向,跳转到显示用户信息//存储existUser//request : 跳转到首页,使用了重定向,会有一个新的请求//servletContext : 如果存储到ServletContext,就意味着所有人都可以拿到你的用户信息!//cookie : 如果存储到cookie中,就是存储到浏览器 , 不安全! cookie中是无法存储中文及一些特殊符号!!//session : 数据存储到服务器!!request.getSession().setAttribute("existUser",existUser);response.sendRedirect("/day57/showIndex");}} catch (SQLException throwables) {throwables.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}}
  • ShowIndexServlet
  @WebServlet(name = "ShowIndexServlet" ,urlPatterns = "/showIndex")public class ShowIndexServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");User existUser = (User) request.getSession().getAttribute("existUser");if (null != existUser) {//在登录状态response.getWriter().write("欢迎回来,"+existUser.getUsername());} else {//不在登录状态//方式一:提示下,未登录//            response.getWriter().write("您还没有登录,<a href='/day57/login.html'>请登录</a>");//方式二:跳转到登录页面response.sendRedirect("/day57/login.html");//看需求,选择方式一还是方式二//登录状态权限管理!!}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}}

第三方jar包,必须放到WEB-INF文件夹中
登录失败使用请求转发、登录成功使用重定向

---------------

9.6.2 随机验证码
  • 显示验证码
 创建图片对象画背景画边框画干扰线产生四位随机数,存储到session画四位随机数将图片响应到浏览器
      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {int width = 60;//定义图片宽度int height = 32;//定义图片高度//创建图片对象BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//创建画笔对象Graphics g = image.getGraphics();//设置背景颜色g.setColor(new Color(0xDCDCDC));g.fillRect(0, 0, width, height);//实心矩形//设置边框g.setColor(Color.black);g.drawRect(0, 0, width - 1, height - 1);//空心矩形Random rdm = new Random();//画干扰椭圆for (int i = 0; i < 50; i++) {int x = rdm.nextInt(width);int y = rdm.nextInt(height);g.drawOval(x, y, 0, 0);}//产生随机字符串String hash1 = Integer.toHexString(rdm.nextInt());//生成四位随机验证码String capstr = hash1.substring(0, 4);//将产生的验证码存储到session域中,方便以后进行验证码校验!request.getSession().setAttribute("existCode", capstr);System.out.println(capstr);g.setColor(new Color(0, 100, 0));g.setFont(new Font("Candara", Font.BOLD, 24));g.drawString(capstr, 8, 24);g.dispose();//将图片响应到浏览器response.setContentType("image/jpeg");OutputStream strm = response.getOutputStream();ImageIO.write(image, "jpeg", strm);strm.close();}
  • 校验验证码
  //获取输入的验证码String validateCode = request.getParameter("validateCode");//将输入的验证码和产生的随机验证码进行校验String existCode = (String) request.getSession().getAttribute("existCode");if (validateCode.equals(existCode)) {//校验通过,完成登录功能} else {//校验不通过,跳转到登录页面}

十 过滤器

10.1 过滤器的概念

滤器就是一个用于在请求之前处理资源的组件

生命周期随着服务器启动而初始化随着请求的发出而过滤随着服务器关闭而销毁执行流程浏览器发起请求服务器会根据这个请求,创建request对象及response对象过滤器会持有request对象及response对象只有当过滤器放行之后,request对象及response对象才会传给Serlvet过滤器链根据配置顺序,遵从"先过滤,后放行"的原则

------------------------------

10.2 过滤器的基本使用

开发步骤自定义类实现Filter接口重写init、doFilter、destroy方法在web.xml中配置过滤器声明过滤器过滤器配置过滤路径
  • 过滤器
  public class Demo01Filter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {//Demo01Filter过滤器的初始化System.out.println("Demo01Filter初始化");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {//Demo01Filter过滤器处理请求System.out.println("Demo01Filter放行之前");filterChain.doFilter(servletRequest,servletResponse);System.out.println("Demo01Filter放行之后");}@Overridepublic void destroy() {//Demo01Filter过滤器的销毁System.out.println("Demo01Filter销毁");}}
  • web.xml
  <!--声明Demo01Filter过滤器--><filter><filter-name>Demo01Filter</filter-name><filter-class>com.qfedu.filter.Demo01Filter</filter-class></filter><!--配置Demo01Filter的过滤路径--><filter-mapping><filter-name>Demo01Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

------------------------------

10.3 过滤器的相关配置

  • 初始化参数

    • Filter配置初始化参数
 <filter><filter-name>Demo03Filter</filter-name><filter-class>com.qfedu.filter.Demo03Filter</filter-class><!--初始化参数--><init-param><param-name>username</param-name><param-value>root</param-value></init-param><init-param><param-name>password</param-name><param-value>root123</param-value></init-param></filter>
  • 初始化参数

    • Filter获取初始化参数
  public class Demo03Filter implements Filter {public void init(FilterConfig config) throws ServletException {Enumeration<String> parameterNames = config.getInitParameterNames();while (parameterNames.hasMoreElements()) {//获取初始化参数名称String parameterName = parameterNames.nextElement();//获取初始化参数值String parameterValue = config.getInitParameter(parameterName);System.out.println("name : " + parameterName + " , value : " + parameterValue);}}......}
  • Filter的过滤路径

    • 针对< servlet-name > ,以为Filter仅针对Demo01Servlet进行过滤
 <filter-mapping><filter-name>Demo03Filter</filter-name><servlet-name>Demo01Servlet</servlet-name></filter-mapping>

---------------

  • Filter的过滤路径

    • 针对< url-pattern >
完全匹配:必须以"/"开头
      <filter-mapping><filter-name>Demo03Filter</filter-name><url-pattern>/aa</url-pattern></filter-mapping>

过滤器只过滤访问路径完全匹配"/aa"的资源

目录匹配:必须以"/"开头,以"*"结尾
      <filter-mapping><filter-name>Demo03Filter</filter-name><url-pattern>/aa/bb/*</url-pattern></filter-mapping>

过滤器只过滤访问路径目录匹配到“/aa/bb“的资源

后缀名匹配:必须以"*"开头,以后缀名结尾
      <filter-mapping><filter-name>Demo03Filter</filter-name><url-pattern>*.jsp</url-pattern></filter-mapping>

过滤器只过滤后缀名为jsp的资源

------------------------------

10.4 过滤器的注解开发

@WebFilter注解WebInitParam[] initParams() default {};     配置初始化参数String filterName() default "";        配置过滤器名称String[] servletNames() default {};      配置过滤的ServletString[] urlPatterns() default {};      配置过滤路径
  • 基本使用
    @WebFilter(filterName = "Demo04Filter" ,urlPatterns = "/demo01",servletNames = "Demo01Servlet" ,initParams = {@WebInitParam(name = "username",value = "root"),@WebInitParam(name = "password",value = "root123")})public class Demo04Filter implements Filter {public void init(FilterConfig config) throws ServletException {Enumeration<String> parameterNames = config.getInitParameterNames();while (parameterNames.hasMoreElements()) {String parameterName = parameterNames.nextElement();String parameterValue = config.getInitParameter(parameterName);System.out.println(parameterName + " , " + parameterValue);}}......}
执行顺序按照过滤器的类名的字典顺序决定谁先过滤,谁先放行比如AFilter、BFilter,那么AFilter就会先过滤,BFilter会先放行

------------------------------

10.5 过滤器案例

10.5.1 中文乱码
    public class EncodingFilter implements Filter {private String encoding = null;public void init(FilterConfig config) throws ServletException {encoding = config.getInitParameter("encoding");}public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {//处理响应中文乱码resp.setContentType("text/html;charset="+encoding);//处理请求中文乱码req.setCharacterEncoding(encoding);chain.doFilter(req, resp);//放行}}
  • web.xml
    <filter><filter-name>EncodingFilter</filter-name><filter-class>com.qfedu.filter.EncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
10.5.2 自动登录
实现步骤登录账户后,根据是否勾选了自动登录选项框,判断是否访问和登录相关资源如果是,直接放行如果不是,判断是否已经在登录状态如果是,直接放行如果不是,需要从cookie中取出存储的用户信息,进行登录操作如果登录成功,直接放行如果登录失败,就跳转到登录页面
  • 登录功能
@WebServlet(name = "LoginServlet" ,urlPatterns = "/login")
public class LoginServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String password = request.getParameter("password");if ("root".equals(username) && "root".equals(password)) {String autoLogin = request.getParameter("autoLogin");System.out.println(autoLogin);if ("autoLogin".equals(autoLogin)) {//进行自动登录,无非就是将用户信息(账户和密码(加密))保存起来!!!//request、servletContext、cookie、sessionCookie cookie = new Cookie("autoLogin",username+"-"+password);cookie.setMaxAge(7 * 24 * 60 * 60);response.addCookie(cookie);}//登录成功,转发到一个页面,用来显示用户信息User existUser = new User();existUser.setUsername(username);existUser.setPassword(password);request.getSession().setAttribute("existUser",existUser);request.getRequestDispatcher("/showIndex").forward(request,response);} else {//登录失败,转到登录页面request.getRequestDispatcher("/index.jsp").forward(request,response);}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
  • LoginFilter自动登录
public class AutoLoginFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {HttpServletRequest request = (HttpServletRequest) req;//获取请求路径String requestURI = request.getRequestURI();//1,判断访问的资源是否和登录相关if (requestURI.contains("login")) {//和登录相关的资源,直接放行chain.doFilter(request, resp);} else {//不是登录相关的资源//2,判断是否在登录状态User existUser = (User) request.getSession().getAttribute("existUser");if (null == existUser) {//不在登录状态 , 进行自动登录//获取CookieCookie cookie = CookieUtils.getCookie(request.getCookies(), "autoLogin");//判断cookie是否为空 , 存在浏览器清理缓存if (null == cookie) {//浏览器清理缓存 , 相当于自动登录失败!! 跳转到登录页面,进行手动登录request.getRequestDispatcher("/login.jsp").forward(request,resp);} else {//还有缓存,进行自动登录//获取用户信息 root-rootString infoStr = cookie.getValue();String[] infos = infoStr.split("-");String username = infos[0];String password = infos[1];if ("root".equals(username) && "root".equals(password)) {//自动登录成功  ,修改登录状态, 直接放行  ,意味着,还不在登录状态!!!existUser = new User();existUser.setUsername(username);existUser.setPassword(password);request.getSession().setAttribute("existUser",existUser);chain.doFilter(req,resp);} else {//自动登录失败 (修改了密码) ,跳转到登录页面,进行手动登录request.getRequestDispatcher("/login.jsp").forward(request,resp);}}} else {//在登录状态 , 直接放行chain.doFilter(request,resp);}}}public void init(FilterConfig config) throws ServletException {}}
10.5.3 敏感词屏蔽
对request对象进行增强。增强获取参数相关方法
放行。传递增强的请求方法
  @WebFilter(filterName = "SensitiveWordsFilter" ,urlPatterns = "/*",initParams = {@WebInitParam(name = "word1",value = "笨蛋"),@WebInitParam(name = "word2" ,value = "傻瓜"),@WebInitParam(name = "word3" ,value = "尼玛"),@WebInitParam(name = "word4",value = "靠")})public class SensitiveWordsFilter implements Filter {//敏感词List<String> sensitiveWords = new ArrayList<>();public void init(FilterConfig config) throws ServletException {Enumeration<String> parameterNames = config.getInitParameterNames();while (parameterNames.hasMoreElements()) {String sensitiveWord = config.getInitParameter(parameterNames.nextElement());sensitiveWords.add(sensitiveWord);}}public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println("SensitiveWordsFilter doFilter");HttpServletRequest request = (HttpServletRequest) req;//增强request下的getParameter方法HttpServletRequest requestPrxoy = (HttpServletRequest) Proxy.newProxyInstance(request.getClass().getClassLoader(),request.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//增强getParameter方法Object returnValue = null;String methodName = method.getName();if ("getParameter".equals(methodName)) {//returnValue就是getParameter方法的返回值,可能会存在敏感词String returnValue1 = (String)method.invoke(request, args);//开始处理敏感词for (String sensitiveWord : sensitiveWords) {if (returnValue1.contains(sensitiveWord)) {//getParameter方法的返回值包含敏感词returnValue1 = returnValue1.replace(sensitiveWord,"***");}}return returnValue1;} else {returnValue = method.invoke(request, args);}return returnValue;}});chain.doFilter(requestPrxoy, resp);}  }

十一 监听器

11.1 监听器的介绍

监听器概念事件源:事件发生的源头监听器:监听事件发生绑定:将监听器绑定到事件源事件:能够触发监听器的事
Servlet监听器事件源:request域对象、session域对象、ServletContext域对象监听器:Servlet三种监听器绑定:配置web.xml事件:域对象发生改变

------------------------------

11.2 监听器的分类

一类监听器        监听域对象的创建、销毁二类监听器        监听域对象中的属性变更(属性设置、属性替换、属性移除)三类监听器        监听域对象的java对象的绑定
11.2.1 一类监听器
ServletRequestListener : 监听ServletRequest域对象的创建、销毁HttpSessionListener :监听HttpSession域对象的创建、销毁ServletContextListener : 监听ServletContext域对象的创建、销毁
开发步骤自定义类实现一类监听器重写监听器中的方法配置web.xml
  • 监听器
  public class MyListener01 implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {//监听ServletContext域的初始化,随着服务器的启动System.out.println("ServletContext初始化");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {//监听ServletContext域的销毁,随着服务器的关闭System.out.println("ServletContext销毁");}}
  • web.xml(绑定)
  <listener><listener-class>com.qfedu.listener.MyListener01</listener-class></listener>
事件源: ServletContext域对象
监听器:ServletContextListener
绑定:  web.xml配置
事件 : ServletContext域对象发生了创建、发生了销毁
11.2.2 二类监听器
ServletRequestAttributeListener :监听ServletRequest域对象中属性变更HttpSessionAttributeListener : 监听HttpSession域对象中属性变更ServletContextAttributeListener : 监听ServletContext域对象中属性变更
  • 监听器
  public class MyServletContextAttributeListener implements ServletContextAttributeListener {@Overridepublic void attributeAdded(ServletContextAttributeEvent scae) {//监听ServletContext域对象中属性添加System.out.println("ServletContext added");}@Overridepublic void attributeReplaced(ServletContextAttributeEvent scae) {//监听ServletContext域对象中属性值被替换System.out.println("ServletContext replaced");}@Overridepublic void attributeRemoved(ServletContextAttributeEvent scae) {//监听ServletContext域对象中属性值移除System.out.println("ServletContext removed");}}
  • web.xml(绑定)
  <listener><listener-class>com.qfedu.listener.MyServletContextAttributeListener</listener-class></listener>
11.2.3 三类监听器
HttpSessionBindingListener监听session域中的java对象的状态(绑定和解绑)绑定:将java对象存储到session域对象解绑:将java对象从session域对象移除
监听器组成事件源:java对象监听器:HttpSessionBindingListener绑定:java对象实现HttpSessionBindingListener接口事件:java对象在session中状态发生改变
  public class User implements HttpSessionBindingListener {@Overridepublic void valueBound(HttpSessionBindingEvent event) {System.out.println("User绑定");}@Overridepublic void valueUnbound(HttpSessionBindingEvent event) {System.out.println("User解绑");}......}

HttpSessionBindingListener监听不需要在web.xml配置

------------------------------

11.3 监听器注解开发

@WebListener 相当于在web.xml绑定了监听器

  @WebListenerpublic class MyServletContextLIstener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("ServletContext创建");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("ServletContext销毁");}}

------------------------------

11.4 监听器综合案例

11.4.1 记录登录人数
  • 开发步骤
 登录功能登录失败,转发到登录页面登录成功,记录登录状态,重定向到首页(显示用户名、注销登录、在线人数)注销登录注销登录成功;正常来说,应该转发到登录页面;转发到首页在线人数使用HttpSessionBindingListener监听器使用ServletContext域对象,存储在线人数count
  • login.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title>
</head>
<body>
<form action="/day59/login" method="post">账户:<input type="text" name="username"/><br>密码:<input type="text" name="password"/><br><button type="submit">登录</button>
</form>
</body>
</html>
  • bean.User
public class User implements HttpSessionBindingListener {@Overridepublic void valueBound(HttpSessionBindingEvent event) {//有人登录成功 , 在线人数(count)加1//判断是否是第一个登录成功的人//获取ServletContextServletContext servletContext = event.getSession().getServletContext();Integer count = (Integer) servletContext.getAttribute("count");if (null == count) {//就是第一个登录成功的人count = 1;} else {//不是第一个登录成功的人count++;}servletContext.setAttribute("count", count);}//在同一个浏览器,意味着是同一个session//第一次登录 ,session.setAttribute("existUser","root") , valueBound  +1//第二次登录 ,session.setAttribute("existUser","root1") , valueBound +1  -> valueUnbound -1@Overridepublic void valueUnbound(HttpSessionBindingEvent event) {//有人注销登录 ,在线人数(count)减1System.out.println("User解绑");ServletContext servletContext = event.getSession().getServletContext();Integer count = (Integer) servletContext.getAttribute("count");count--;servletContext.setAttribute("count", count);}private Integer id;private String username;private String password;public User() {}public User(Integer id, String username, String password) {this.id = id;this.username = username;this.password = password;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}

在线人数:在同一个浏览器,操作多次登录,意味着是同一个session

  • LoginServlet
@WebServlet(name = "LoginServlet", urlPatterns = "/login")
public class LoginServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String password = request.getParameter("password");if ("root".equals(username) && "root".equals(password)) {//登录成功 , 修改登录状态 ,跳转到ShowIndexServletUser existUser = new User();existUser.setUsername(username);existUser.setPassword(password);request.getSession().setAttribute("existUser", existUser);
//            request.getRequestDispatcher("/showIndex").forward(request,response);response.sendRedirect("/day59/showIndex");} else {//登录失败,转发到登录页面,重新登录request.getRequestDispatcher("/login.html").forward(request, response);}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
  • LogoutServlet
@WebServlet(name = "LogoutServlet", urlPatterns = "/logout")
public class LogoutServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//注销登录 , 将existUser变量从session域中移除!
//        request.getSession().removeAttribute("existUser");//注销登录,将session销毁 -> 将existUser变量从session域中移除!request.getSession().invalidate();//注销成功request.getRequestDispatcher("/showIndex").forward(request, response);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
  • ShowIndexServlet
@WebServlet(name = "ShowIndexServlet", urlPatterns = "/showIndex")
public class ShowIndexServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {User existUser = (User) request.getSession().getAttribute("existUser");StringBuffer responseBody = new StringBuffer();if (null == existUser) {//不在登录状态,提示responseBody.append("您还没有登录;<a href='/day59/login.html'>请登录</a><br>");} else {//在登录状态,显示信息responseBody.append("欢迎回来," + existUser.getUsername() + "   <a href='/day59/logout'>注销</a><br>");}ServletContext servletContext = getServletContext();//获取在线人数countInteger count = (Integer) servletContext.getAttribute("count");System.out.println("在线人数 " + count);//count变量为null,在没有任何人登录状态下,访问了ShowIndexServletif (null == count) {//没有任何人在登录状态 ,在线人数处理成0人count = 0;} else {//有人在登录状态 ,直接输出在线人数count人}responseBody.append("在线人数 : " + count);response.setContentType("text/html;charset=utf-8");response.getWriter().write(responseBody.toString());}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

十二 JavaWeb综合案例

12.1 用户管理与DML操作

12.1.1 用户列表
开发步骤获取用户列表放到首页完成登录状态才需要获取用户列表
  • UserDao
      @Overridepublic List<User> selectUserList() throws Exception {return new QueryRunner(JDBCUtil.getDataSource()).query("select * from tb_user",new BeanListHandler<User>(User.class));}
  • ShowIndexSerlvet
  @WebServlet(name = "ShowIndexServlet" ,urlPatterns = "/showIndex")public class ShowIndexServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {User existUser = (User) request.getSession().getAttribute("existUser");StringBuffer responseBody = new StringBuffer();if (null != existUser) {//已经在登录状态responseBody.append("欢迎回来~ " + existUser.getUsername());responseBody.append(" <a href='/day60/logout'>注销</a><br>");//获取用户列表UserDao userDao = new UserDaoImpl();try {List<User> userList = userDao.selectUserList();System.out.println(userList);responseBody.append("<table border='1px' cellspaceing='0px' cellpadding='10px' width='500px' height='200px'>");responseBody.append("<tr>");responseBody.append("<td>ID</td>");responseBody.append("<td>账户</td>");responseBody.append("<td>密码</td>");responseBody.append("</tr>");for (User user : userList) {//遍历一个User对象,对应就应该有一个trresponseBody.append("<tr>");responseBody.append("<td>"+user.getId()+"</td>");responseBody.append("<td>"+user.getUsername()+"</td>");responseBody.append("<td>"+user.getPassword()+"</td>");responseBody.append("</tr>");}responseBody.append("</table>");} catch (Exception e) {e.printStackTrace();}} else {//不在登录状态responseBody.append("您还没有登录,<a href='/day60/login.html'>请登录</a><br>");}response.setContentType("text/html;charset=utf-8");response.getWriter().write(responseBody.toString());}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}}
12.1.2 删除用户
开发步骤首页,给每一个记录后面添加一个删除按钮用户列表不要显示当前登录用户
  • UserDao
      @Overridepublic void deleteUserById(Integer id) throws Exception {new QueryRunner(JDBCUtil.getDataSource()).update("delete from tb_user where id = ?",id);}
  • ShowIndexServlet
  responseBody.append("<table border='1px' cellspaceing='0px' cellpadding='10px' width='500px' height='200px'>");responseBody.append("<tr>");responseBody.append("<td>ID</td>");responseBody.append("<td>账户</td>");responseBody.append("<td>密码</td>");responseBody.append("<td>操作</td>");responseBody.append("</tr>");for (User user : userList) {if ( user.getId() != existUser.getId()) {//遍历一个User对象,对应就应该有一个trresponseBody.append("<tr>");responseBody.append("<td>"+user.getId()+"</td>");responseBody.append("<td>"+user.getUsername()+"</td>");responseBody.append("<td>"+user.getPassword()+"</td>");responseBody.append("<td><a href='/day60/deleteUser?id="+user.getId()+"'>删除</a></td>");responseBody.append("</tr>");}}responseBody.append("</table>");
  • DeleteUserServlet
  @WebServlet(name = "DeleteUserServlet" ,urlPatterns = "/deleteUser")public class DeleteUserServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String idStr = request.getParameter("id");Integer id = Integer.parseInt(idStr);UserDao userDao = new UserDaoImpl();try {userDao.deleteUserById(id);} catch (Exception e) {e.printStackTrace();}response.sendRedirect("/day60/showIndex");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}}
12.1.3 批量删除
开发流程在首页需要给每一个记录新加多选框当点击批量删除按钮之后,完成批量删除操作
  • UserDao
      public void deleteUsersByIds(List<Integer> idList) throws Exception {for (Integer id : idList) {deleteUserById(id);}}
  • ShowIndexServlet
  responseBody.append("<form action='/day60/deleteUsers' method='post'>");responseBody.append("<table border='1px' cellspaceing='0px' cellpadding='10px' width='500px' height='200px'>");responseBody.append("<tr>");responseBody.append("<td></td>");responseBody.append("<td>ID</td>");responseBody.append("<td>账户</td>");responseBody.append("<td>密码</td>");responseBody.append("<td>操作</td>");responseBody.append("</tr>");for (User user : userList) {if ( user.getId() != existUser.getId()) {//遍历一个User对象,对应就应该有一个trresponseBody.append("<tr>");responseBody.append("<td><input name='ids' type='checkbox' value='"+user.getId()+"'></td>");......responseBody.append("</tr>");}}responseBody.append("</table>");responseBody.append("<button type='submit'>批量删除</button>");responseBody.append("</form>");
12.1.4 添加用户
开发步骤首页加入一个添加用户按钮点击添加用户按钮进入到登录页面
  • UserDao
      public void addUser(User inputUser) throws Exception {new QueryRunner(JDBCUtil.getDataSource()).update("insert into tb_user(username ,password) values(?,?)",inputUser.getUsername(),inputUser.getPassword());}
  • ShowIndexServlet
  //已经在登录状态responseBody.append("欢迎回来~ " + existUser.getUsername());responseBody.append(" <a href='/day60/logout'>注销</a><br>");responseBody.append("<a href='/day60/add.html'>添加用户</a><br>");
  • AddUserServlet
  @WebServlet(name = "AddUserServlet" ,urlPatterns = "/addUser")public class AddUserServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String username = request.getParameter("username");String password = request.getParameter("password");User inputUser = new User();inputUser.setUsername(username);inputUser.setPassword(password);//方式一:在添加之前,校验下用户名是否存在//方式二:让username字段有唯一约束!UserDao userDao = new UserDaoImpl();try {userDao.addUser(inputUser);//添加成功,跳转到首页response.sendRedirect("/day60/showIndex");} catch (Exception e) {e.printStackTrace();//添加失败,跳转到添加用户页面response.sendRedirect("/day60/add.html");}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}}
12.1.5 修改用户
开发步骤首页加入修改按钮
  • UserDao
      @Overridepublic void updateUser(User user) throws Exception {new QueryRunner(JDBCUtil.getDataSource()).update("update tb_user set username = ? , password = ? where id = ?",user.getUsername(),user.getPassword(),user.getId());}
  • ShowIndexServlet
  for (User user : userList) {if ( user.getId() != existUser.getId()) {//遍历一个User对象,对应就应该有一个trresponseBody.append("<tr>");responseBody.append("<td><input name='ids' type='checkbox' value='"+user.getId()+"'></td>");responseBody.append("<td>"+user.getId()+"</td>");responseBody.append("<td>"+user.getUsername()+"</td>");responseBody.append("<td>"+user.getPassword()+"</td>");responseBody.append("<td>" +"<a href='/day60/deleteUser?id="+user.getId()+"'>删除</a> " +"<a href='/day60/showUpdateUser?id="+user.getId()+"'>修改</a>"+"</td>");responseBody.append("</tr>");}}
  • ShowUpdateUserServlet 显示修改用户页面
  @WebServlet(name = "ShowUpdateUserServlet" , urlPatterns = "/showUpdateUser")public class ShowUpdateUserServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Integer id = Integer.parseInt(request.getParameter("id"));//根据id查询用户UserDao userDao = new UserDaoImpl();StringBuffer responseBody = new StringBuffer();try {User user = userDao.selectUserById(id);System.out.println(user);responseBody.append("<form action='/day60/updateUser' method='post'>");responseBody.append("<input type='hidden' name='id' value='"+user.getId()+"'/>");responseBody.append("账户:<input type='text' name='username' value='"+user.getUsername()+"'/><br>");responseBody.append("密码:<input type='text' name='password' value='"+user.getPassword()+"'/><br>");responseBody.append("<button type='submit'>修改</button>");responseBody.append("</form>");} catch (Exception e) {e.printStackTrace();}response.setContentType("text/html;charset=utf-8");response.getWriter().write(responseBody.toString());}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}}
  • UpdateUserServlet 修改用户
  @WebServlet(name = "UpdateUserServlet" ,urlPatterns = "/updateUser")public class UpdateUserServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Integer id = Integer.parseInt(request.getParameter("id"));String username = request.getParameter("username");String password = request.getParameter("password");System.out.println("username : " + username + ", password : " + password);//要修改的内容:username、passwordUser user = new User(id,username,password);UserDao userDao = new UserDaoImpl();try {userDao.updateUser(user);//修改成功,跳转到首页response.sendRedirect("/day60/showIndex");} catch (Exception e) {e.printStackTrace();//修改失败,跳转到修改页面response.sendRedirect("/day60/showUpdateUser?id="+id);}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}}

完整版案例

12.2 BaseServlet优化案例

12.2.1 BaseServlet 的作用

让一个Servlet可以处理多种不同的请求,不同的请求调用Servlet的不同方法。

12.2.2 实现原理
客户端发送请求时, 必须多给出一个参数, 用来说明要调用的方法。这样,BaseServlet 通过该参数来
调用目标方法。请求处理方法的签名必须与 service 相同, 即方法的返回值和参数,以及声明的异常都相同。
12.2.3 BaseServlet的应用
  @WebServlet(name = "UserServlet",urlPatterns = "/user")public class UserServlet extends BaseServlet {public void login(HttpServletRequest request,HttpServletResponse response){String username = request.getParameter("username");String password = request.getParameter("password");User inputUser = new User();inputUser.setUsername(username);inputUser.setPassword(password);UserDao userDao = new UserDaoImpl();try {User existUser = userDao.login(inputUser);if (null == existUser) {//登录失败request.getRequestDispatcher("/login.html").forward(request,response);} else {//登录成功request.getSession().setAttribute("existUser",existUser);response.sendRedirect("/day61/user?methodName=showIndex");}} catch (Exception e) {e.printStackTrace();}}public void showIndex(HttpServletRequest request , HttpServletResponse response) throws Exception {System.out.println("showIndex");User existUser = (User) request.getSession().getAttribute("existUser");StringBuffer responseBody = new StringBuffer();if (null != existUser) {//在登录状态responseBody.append("欢迎回来~~~"+existUser.getUsername());responseBody.append("<a href='/day61/user?methodName=logout'>注销登录</a>");} else {//不在登录状态responseBody.append("您还没有登录;");responseBody.append("<a href='/day61/login.html'>请登录</a>");}response.setContentType("text/html;charset=utf-8");response.getWriter().write(responseBody.toString());}public void logout(HttpServletRequest request , HttpServletResponse response) throws Exception {request.getSession().invalidate();response.sendRedirect("/day61/login.html");}}
12.2.4 BaseServlet的优化
资源跳转问题
响应正文中文乱码
  @WebServlet(name = "BaseServlet",urlPatterns = "/base")public class BaseServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");String methodName = request.getParameter("methodName");try {Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);if (null != method) {//处理返回值,为了资源跳转String returnValue = (String) method.invoke(this,request,response);System.out.println(returnValue);//有的方法有返回值//登录成功:重定向 redirect:/day61/user?methodName=showIndex//登录失败: 请求转发 forward:/login.html//有的方法没有返回值//null,不用做任何处理if (returnValue != null){//有返回值,实现资源跳转,需要资源的路径if (returnValue.lastIndexOf(":") != -1) {String path = returnValue.split(":")[1];System.out.println("path : "+path);//有":"//实现资源跳转:重定向、请求转发if (returnValue.startsWith("redirect")) {//重定向response.sendRedirect(request.getContextPath()+path);} else if(returnValue.startsWith("forward")){//请求转发request.getRequestDispatcher(path).forward(request,response);}} else {//没有":",默认就是转发  /login.htmlrequest.getRequestDispatcher(returnValue).forward(request,response);}} else {//不做任何处理}}} catch (Exception e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}}

12.3 jsp优化登录案例

之前方案login.html登录页面LoginServlet处理登录请求业务处理调用dao,操作数据ShowIndexServlet(java代码)显示用户名存在的问题login.html无法和java后台进行交互,无法显示错误信息ShowIndexServlethtml无法和java后台进行交互,java代码应该专注于后台代码
现在方案login.jsp登录页面显示错误信息LoginServlet处理登录请求业务处理调用dao,操作数据index.jsp显示用户名
  • login.jsp
  <%--显示错误信息--%><%="<font color='red'>" + (request.getAttribute("errorMsg") == null ? "" : request.getAttribute("errorMsg") ) + "</font>"%><form action="/day62/user" method="post"><input type="hidden" name="methodName" value="login"/>账户:<input type="text" name="username"/><br>密码:<input type="text" name="password"/><br><button type="submit">登录</button></form>
  • index.jsp
  <%String username = (String) session.getAttribute("username");if (null == username) {//不在登录状态out.write("您还没有登录;");out.write("<a href='/day62/login.jsp'>请登录</a>");} else {//在登录状态out.write("欢迎回来~~~"+username);}%>
存在的问题jsp页面还存在java代码(后台代码)和html代码(前端代码)融合在一起的问题!一定程度解决,可能需要jstl标签库。彻底解决,得使用vue + html

12.4 三层结构优化

12.4.1 准备工作
环境准备tomcat8.5idea2020.1jdk1.8
导入jar包BeanUtilsDbUtilsc3p0mysql驱动jstl
12.4.2 登录
 开发流程UserServletlogin方法  调用UserService的login方法UserServicelogin方法,返回User对象     调用UserDao的login方法UserDaologin方法,返回User对象     操作数据库,并将记录封装到User对象登录成功修改登录状态,重定向到首页登录失败记录错误信息,请求转发到登录页面
  • UserDao
      @Overridepublic User login(User inputUser) throws Exception {return new QueryRunner(JDBCUtils.getDataSource()).query("select * from tb_user where username = ? and password = ?",new BeanHandler<User>(User.class),inputUser.getUsername(),inputUser.getPassword());}
  • UserService
      @Overridepublic User login(User inputUser) throws Exception {UserDao userDao = new UserDaoImpl();return userDao.login(inputUser);}
  • UserServlet类的login方法
      private UserService userService = new UserServiceImpl();public String login(HttpServletRequest request,HttpServletResponse response){User inputUser = new User();//将请求参数封装到inputUser中try {BeanUtils.populate(inputUser,request.getParameterMap());User existUser = userService.login(inputUser);//没有异常有返回值if (null != existUser) {//登录成功 , 修改登录状态,跳转到首页request.getSession().setAttribute("existUser",existUser);return "redirect:/index.jsp";} else {//登录失败 ,记录错误信息,跳转到登录页面request.setAttribute("errorMsg","账户或密码错误");return "/login.jsp";}} catch (Exception e) {e.printStackTrace();}//有异常,应该有返回值 。意味着登录失败,返回登录页面,重新登录return "/login.jsp";}
  • login.jsp
  <body><font color="red">${errorMsg}</font><form action="${pageContext.request.contextPath}/user" method="post"><input type="hidden" name="methodName" value="login"/>账户:<input type="text" name="username"/><br>密码:<input type="text" name="password"/><br><button type="submit">登录</button></form></body>
  • index.jsp
  <body><%--在登录状态显示用户名--%><c:if test="${existUser != null}">欢迎回来~~~  ${existUser.username}  <a href="${pageContext.request.contextPath}/user?methodName=logout">注销</a></c:if><%--不在登录状态提示登录--%><c:if test="${existUser == null}">您还没有登录,<a href="${pageContext.request.contextPath}/login.jsp">请登录</a></c:if></body>
12.4.3 注销登录
开发步骤login.jsp上需要加一个“注销”的按钮注销成功   跳转到登录页面注销失败 跳转到首页,重新进行手动注销
  • UserServlet
    public String logout(HttpServletRequest request,HttpServletResponse response){try {request.getSession().invalidate();return "redirect:/login.jsp";} catch (Exception e) {e.printStackTrace();return "/index.jsp";}}
12.4.4 用户列表
开发步骤登录成功,重定向到UserServlet中的selectUserList方法在selectUserList方法中获取用户列表,并将其保存再请求转发到index.jsp
  • UserDao
      @Overridepublic List<User> selectUserList() throws Exception {return new QueryRunner(JDBCUtils.getDataSource()).query("select * from tb_user",new BeanListHandler<User>(User.class));}
  • UserServlet类的selectUserList方法
      public String selectUserList(HttpServletRequest request,HttpServletResponse response) throws Exception {List<User> userList = userService.selectUserList();request.getSession().setAttribute("userList",userList);return "/index.jsp";}
  • index.jsp
  <body><%--在登录状态显示用户名--%><c:if test="${existUser != null}">欢迎回来~~~  ${existUser.username}  <a href="${pageContext.request.contextPath}/user?methodName=logout">注销</a><%--显示用户列表--%><table border="1px" cellspacing="0px" cellpadding="15px" width="500px" height="200px"><tr><td>ID</td><td>账户</td><td>密码</td></tr><c:forEach items="${userList}" var="user"><tr><td>${user.id}</td><td>${user.username}</td><td>${user.password}</td></tr></c:forEach></table></c:if><%--不在登录状态提示登录--%><c:if test="${existUser == null}">您还没有登录,<a href="${pageContext.request.contextPath}/login.jsp">请登录</a></c:if></body>
12.4.5 登录校验
需求:只要不在登录状态就自动跳转到登录页面
开发步骤定义过滤器  判断是否和登录相关和登录相关,直接放行访问登录页面处理登录,请求参数methodName="login"和登录无关,进行登录状态判断不在登录状态,跳转到login.jsp在登录状态,直接放行
  • filter.LoginFilter
  @WebFilter(filterName = "LoginFilter" ,urlPatterns = "/*")public class LoginFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println("LoginFilter doFilter");HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;//登录校验String requestURI = request.getRequestURI();String methodName = request.getParameter("methodName");if (requestURI.contains("login") || ( methodName != null && methodName.equals("login"))) {//和登录相关的资源,直接放行chain.doFilter(req, resp);} else {//和登录无关的资源Object existUser = request.getSession().getAttribute("existUser");if (null == existUser) {//不在登录状态,跳转到login.jspresponse.sendRedirect("/day64/login.jsp");}  else {//在登录状态,直接放行chain.doFilter(req, resp);}}}public void init(FilterConfig config) throws ServletException {}}
12.4.6 删除用户
开发步骤给table每一行加删除按钮不管是删除成功,还是删除失败,都应该重新获取用户列表并显示转发到UserServlet类的selectUserList方法
  • index.jsp
  ......<c:forEach items="${userList}" var="user"><tr><td>${user.id}</td><td>${user.username}</td><td>${user.password}</td><td><a href="${pageContext.request.contextPath}/user?methodName=deleteUserById&id=${user.id}">删除</a></td></tr></c:forEach>......
  • UserDao
      @Overridepublic int deleteUserById(Integer id) throws Exception {return new QueryRunner(JDBCUtils.getDataSource()).update("delete from tb_user where id = ?",id);}
  • UserService
      @Overridepublic boolean deleteUserById(Integer id) throws Exception {return userDao.deleteUserById(id) == 1;}
  • UserServlet的deleteUserById方法
      public String deleteUserById(HttpServletRequest request,HttpServletResponse response){Integer id = Integer.parseInt(request.getParameter("id"));try {boolean flag = userService.deleteUserById(id);} catch (Exception e) {e.printStackTrace();}//获取用户列表return "/user?methodName=selectUserList";}
12.4.7 修改用户
开发步骤在table的每一行中加修改按钮当点击table中修改按钮,跳转到UserServlet类中的toUpdateUserById方法UserServlet类中的toUpdateUserById方法获取用户信息跳转到修改用户页面当点击修改页面中的修改按钮,开始修改修改成功,跳转到UserServlet类中的selectUserList方法修改失败,跳转到toUpdateUserById方法,让它重新进行修改用户
  • UserDao
      @Overridepublic void updateUserById(User inputUser) throws Exception {new QueryRunner(JDBCUtils.getDataSource()).update("update tb_user set username = ? , password = ? where id = ?",inputUser.getUsername(),inputUser.getPassword(),inputUser.getId());}
  • UserServlet类toUpdateUserById方法
      public String toUpdateUserById(HttpServletRequest request,HttpServletResponse response) {Integer id = Integer.parseInt(request.getParameter("id"));User user = null;try {user = userService.selectUserById(id);} catch (Exception e) {e.printStackTrace();}request.setAttribute("user",user);return "/updateUser.jsp";}
  • updateUser.jsp
  <body><font color="red">${errorMsg}</font><form action="${pageContext.request.contextPath}/user" method="post"><input type="hidden" name="methodName" value="updateUserById"/><input type="hidden" name="id" value="${user.id}">账户:<input type="text" name="username" value="${user.username}"><br>密码:<input type="text" name="password" value="${user.password}"><br><button type="submit">修改</button></form></body>
  • UserServlet类updateUserById方法
      public String updateUserById(HttpServletRequest request,HttpServletResponse response){User inputUser = new User();try {BeanUtils.populate(inputUser,request.getParameterMap());userService.updateUserById(inputUser);//修改成功return "/user?methodName=selectUserList";} catch (Exception e) {e.printStackTrace();}request.setAttribute("errorMsg","修改失败");//修改失败return "/user?methodName=toUpdateUserById&id="+inputUser.getId();}

十三 分页查询

分页查询概念在MySQL知识点总结10.8

13.1 数据库的物理分页

select * from 表名 limit ? , ?
#第一个?:开始查询脚标(从0开始)
#第二个?:查询多少个
# 需求:每页数据有2条-- 第一页 1、2;开始脚标为0-- 从脚标为0的记录开始,往后查2个!SELECT * FROM tb_user LIMIT 0 , 2;-- 第二页 3、5;开始脚标为2SELECT * FROM tb_user LIMIT 2 , 2;-- 第三页 7、8;开始脚标为4SELECT * FROM tb_user LIMIT 4 , 2;-- 第四页 12;开始脚标为6SELECT * FROM tb_user LIMIT 6 , 2;

13.2 分页查询流程分析

问题一:当浏览器发起分页请求时,浏览器需要传递什么参数给服务器?
答:当前页数问题二:当服务器响应浏览器时,服务器需要传递什么参数给浏览器?
答:都是浏览器需要的数据;如下:当前页数(currentPage)总页数(totalPage)总记录数(totalSize)每页记录数(pageSize)当前页数据(list)问题三:当服务器向浏览器响应上面的五个参数时,是将五个参数作为整体传递还是独立传递?
答:服务器向浏览器传递参数,无非是通过域!如果是独立传递,那么就需要在域中存储五个参数(currentPage、totalPage、totalSize、pageSize、list)如果是整体传递,那么只需要在域中存储一个参数(PageBean)
总结:将五个参数作为整体问题四:分页对象PageBean中的五个参数是在哪一层代码中确定的?
答:当前页数(currentPage):controller层总页数(totalPage):service层总记录数(totalSize):获取是在dao层,调用是在service层每页记录数(pageSize):service层当前页数据(list):获取是在dao层
总结:以上五个参数封装成分页对象(PageBean),是在service层进行的

13.3 分页代码实现

步骤:确定每页显示数据数量。确定分页显示所需总页数编写SQL查询语句,实现数据查询在JSP页面中进行分页显示设置
pageSize = 10 //每页10条数据
total = 100; //一共100条数据 分10页
total = 105; // 一共105条数据 分11页if(total % pageSize == 0){num = total / pageSize; //页数
}
if(total % pageSize != 0){num = total / pageSize + 1; //页数
}int pageNum ; //当前页码
limit (pageNum-1)*pageSize,pageSize //sql语句
13.3.1 后台代码
  • UserServlet
处理当前页数
获取分页对象PageBean
页面跳转
      public String selectUserListByPage(HttpServletRequest request, HttpServletResponse response){String currentPageStr = request.getParameter("currentPage");Integer currentPage = getCurrentPage(currentPageStr);//调用UserService,传递currentPagetry {PageBean<User> pageBean = userService.selectUserListByPage(currentPage);System.out.println(pageBean);request.setAttribute("pageBean",pageBean);//转发到用户列表页面return "/userList.jsp";} catch (Exception e) {e.printStackTrace();}return "/index.jsp";}
  • UserService
设置当前页数(currentPage)
设置总记录数(totalSize)
设置每页记录数(pageSize)
设置总页数(totalPage)    总页数 = (总记录数 % 每页记录数 == 0) ? 总记录数/ 每页记录数 : 总记录数/ 每页记录数 + 1;
设置当前页数据(list)   begin = (currentPage - 1) * pageSize
      public PageBean<User> selectUserListByPage(Integer currentPage) throws Exception {PageBean<User> pageBean = new PageBean<>();//    currentPage;当前页数pageBean.setCurrentPage(currentPage);//    totalSize;总记录数UserDao userDao = new UserDaoImpl();Integer totalSize = userDao.selectTotalSize();pageBean.setTotalSize(totalSize);//    pageSize;每页记录数Integer pageSize = 3;pageBean.setPageSize(pageSize);//    totalPage:总页数  = 总记录数 / 每页记录数Integer totalPage = ( totalSize % pageSize == 0 ) ? ( totalSize / pageSize ) : (totalSize / pageSize + 1 ) ;pageBean.setTotalPage(totalPage);//    list;当前页数据//select * from tb_user limit ? , ?//第一个? : 开始脚标 = (当前页数 - 1) * 每页记录数//第二个? : 查询多少个 (每页记录数) pageSizeInteger begin = (currentPage - 1) * pageSize;List<User> list = userDao.selectUserListByPage(begin, pageSize);pageBean.setList(list);return pageBean;}
  • UserDao
获取总记录数
获取当前页数据
  public class UserDaoImpl implements UserDao {@Overridepublic Integer selectTotalSize() throws Exception {return new QueryRunner(JDBCUtils.getDataSource()).query("select * from tb_user",new BeanListHandler<User>(User.class)).size();}@Overridepublic List<User> selectUserListByPage(Integer begin, Integer pageSize) throws Exception {return new QueryRunner(JDBCUtils.getDataSource()).query("select * from tb_user limit ? , ?" ,new BeanListHandler<User>(User.class),begin,pageSize);}}
13.3.2 前端代码
  <body><table border="1px" cellspacing="0px" cellpadding="10px" width="600px" height="200px"><tr><td>ID</td><td>账户</td><td>密码</td></tr><c:forEach items="${pageBean.list}" var="user"><tr><td>${user.id}</td><td>${user.username}</td><td>${user.password}</td></tr></c:forEach><%--分页工具条--%><tr><td colspan="3" align="center">第${pageBean.currentPage}/${pageBean.totalPage}页总记录数:${pageBean.totalSize}每页显示${pageBean.pageSize}条<c:if test="${pageBean.currentPage != 1}"><a href="${pageContext.request.contextPath}/user?methodName=selectUserListByPage&currentPage=1"> [首页] </a><a href="${pageContext.request.contextPath}/user?methodName=selectUserListByPage&currentPage=${pageBean.currentPage-1}"> [上一页] </a></c:if><c:if test="${pageBean.currentPage != pageBean.totalPage}"><a href="${pageContext.request.contextPath}/user?methodName=selectUserListByPage&currentPage=${pageBean.currentPage+1}"> [下一页] </a><a href="${pageContext.request.contextPath}/user?methodName=selectUserListByPage&currentPage=${pageBean.totalPage}"> [尾页] </a></c:if></td></tr></table></body>

13.4 另一版本

通过Page类分页查询


十四 文件上传

14.1 概念及原理

本质就是将一台电脑中的文件根据网络协议通过io流传递到另外一台电脑(服务器)上

网络编程ip:电脑在网络中的唯一标识port:软件在电脑中的唯一标识协议:不同设备进行沟通的规则!
概念:当用户在前端页面点击文件上传后,文件数据交给服务器端,实现保存
步骤:   编写文件上传表单编写服务器程序接收文件

文件上传表单提交方式:post
表单提交类型:mulitipart/form-data

14.2 页面实现

<form action="" method="post" enctype="multipart/form-data">文件:<input type="file" name="up"><input type="submit" value="上传">
</form>

14.3 编写服务器程序

核心步骤:· 编写Servlet· 使用@MultipartConfig注解· 使用javax.servlet.http.Part接口接收文件类型
14.3.1 文件上传
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;/*** 文件上传* 如果让Servlet支持文件上传,需要加一个注解@MultipartConfig(servlet3.0以后才有)*/
@WebServlet(name = "UploadServlet", urlPatterns = "/upload")
// maxFileSize单个文件大小,单位字节;
// maxRequestSize请求中多个文件的总大小;
@MultipartConfig(maxFileSize = 1024 * 1024, maxRequestSize = 1024 * 1024 * 2)
public class UploadServlet extends HttpServlet {// 限制上传文件类型private List<String> FILE_TYPES = new ArrayList<>();public UploadServlet() {FILE_TYPES.add(".jpg");FILE_TYPES.add(".png");FILE_TYPES.add("gif");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//拿到文件Part part = request.getPart("up");String fileName = part.getSubmittedFileName();//用户上传的文件名String ext = fileName.substring(fileName.lastIndexOf("."));//扩展名PrintWriter writer = response.getWriter();if (FILE_TYPES.contains(ext)) {part.write("D:\\upload\\" + System.currentTimeMillis() + ext);//以文件流的形式存入磁盘,加上时间戳writer.write("上传成功");} else {writer.write("文件格式错误");}}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
13.3.2 文件下载
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.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;@WebServlet(name = "DownloadServlet", urlPatterns = "/download")
public class DownloadServlet extends HttpServlet {private String path = "D:\\load\\";// 服务端存放文件的地方@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String name = request.getParameter("name");response.setHeader("content-disposition","attachment:filename="+ URLEncoder.encode(name,"utf-8"));File file = new File(path+name);FileInputStream inputStream = new FileInputStream(file);//从系统中读取文件ServletOutputStream outputStream = response.getOutputStream();// 响应流// 从水池1中取水,放到水池2byte[] buf = new byte[1024];//水桶int len = 0;//水桶每次从水池1拿多少水,等于-1,代表水池已经空了while ((len = inputStream.read(buf))!=-1) {//从水池1中给水桶灌水outputStream.write(buf,0,len);//把水桶里的水,倒进水池2,偏移量 最后一次可能桶没装满}outputStream.close();inputStream.close();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
13.3.3 多文件上传
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;@WebServlet(name = "MutilUploadServlet", urlPatterns = "/mutilupload")
@MultipartConfig(maxFileSize = 1024 * 1024, maxRequestSize = 1024 * 1024 * 2)
public class MutilUploadServlet extends HttpServlet {private List<String> FILE_TYPES = new ArrayList<>();@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");//拿到文件Collection<Part> parts = request.getParts();//多文件上传,拿到的是请求中所有的内容,包括文字和文件for (Part part : parts) {String name = part.getName();//参数名String fileName = part.getSubmittedFileName();//代表当前的part是一个文字参数,文字参数没有文件名if (fileName != null) {//是文件System.out.println("文件名" + fileName);System.out.println(request.getRemoteAddr());String ext = fileName.substring(fileName.lastIndexOf("."));PrintWriter writer = response.getWriter();if (FILE_TYPES.contains(ext)) {part.write("D:\\upload\\" + System.currentTimeMillis() + ext);//以文件流的形式,写入磁盘writer.write("上传成功");} else {writer.write("文件格式错误");}} else {System.out.println(name + "=" + request.getParameter(name));}}}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}

十五 BaseServlet

BaseServlet

Java Web总结相关推荐

  1. 在k8s中使用gradle构建java web项目镜像Dockerfile

    在k8s中使用gradle构建java web项目镜像Dockerfile FROM gradle:6-jdk8 AS build COPY --chown=gradle:gradle . /home ...

  2. Jenkins 2.16.3默认没有Launch agent via Java Web Start,如何配置使用

    问题:Jenkins 2.16.3默认没有Launch agent via Java Web Start,如下图所示,而这种启动方式在Windows上是最方便的. 如何设置才能让出来呢? 打开&quo ...

  3. Java Web项目结构

    Java Web项目结构(一般) 1.Java src 2.JRE System Library 3.Java EE 6 Libraries 4.Web App Libraries 5.WebRoot ...

  4. Java Web 中的一些问题

    http://localhost:8080/struts2demo/online/userLogin.jsp 请求模式 :// 主机名名称(或者服务器名称) : 端口 / Servlet容器的名称(通 ...

  5. java web ubuntu_Ubuntu部署Java web项目

    登录服务器和给服务器传输文件,使用的工具是Xshell Xftp Mysql 安装mysql 输入:sudo apt-get update                     更新软件列表 输入: ...

  6. JAVA Web项目中所出现错误及解决方式合集(不断更新中)

    JAVA Web项目中所出现错误及解决方式合集 前言 一.几个或许会用到的软件下载官网 二.Eclipse的[preferences]下没有[sever]选项 三.Tomcat的安装路径找不到 四.T ...

  7. 使用Netbeans创建java Web项目

     使用Netbeans创建java Web项目 需要先搭建JDK参考: Java开发环境的搭建以及使用eclipse创建项目 Linux环境安装卸载JDK 1.安装Tomcat 去官网下载最新的T ...

  8. java axis2 开发_基于Apache axis2开发Java Web服务

    1.安装配置axis2环境 下载好后把axis2-1.4.1-war目录下面的axis2.war发布到tomcat的webapps中. 发布好,访问:http://localhost:8079/axi ...

  9. java web三大组件之filter过滤器

    过滤器是java web中相当重要的组成成分,是JavaWeb三大组件之一,它与Servlet很相似.不过过滤器有以下三条特性: 过滤器是用来拦截请求的,而不是处理请求的. 当用户请求某个Servle ...

  10. java web学习项目20套源码完整版

    java web学习项目20套源码完整版 自己收集的各行各业的都有,这一套源码吃遍所有作业项目! 1.BBS论坛系统(jsp+sql) 2.ERP管理系统(jsp+servlet) 3.OA办公自动化 ...

最新文章

  1. 赋值语句和赋值表达式
  2. 【Linux】时间同步设置+防火墙设置+SELinux设置
  3. 002_Java日志
  4. Desktop OS Market Share: Windows 90% - Mac 9% - Linux 1%
  5. linux 查看空间(内存、磁盘、文件目录、分区)的几个命令
  6. linux服务器 缓存,Linux服务器内存使用分析及内存缓存
  7. Castle 开发系列文章
  8. shell编程规范与变量2
  9. vrep和simulink联合仿真
  10. C#获取电脑硬盘序列号
  11. ensp mstp+vrrp配置实验
  12. 不再当码农-Flash AS3.0多个影片剪辑实现同一功能循环问题
  13. 因果AI热度背后的打靶迷局
  14. jmeter性能测试步骤实战教程
  15. 【LOD for 3D Graphics】LOD技术背景调查
  16. Edman降解蛋白测序法的基本步骤解析:耦合和裂解过程
  17. 无线安全专题_破解篇03--打造个人字典
  18. 爬虫 http原理,梨视频,github登陆实例,requests请求参数小总结
  19. 孩子发烧,别急着降温
  20. 尝试用 vue 实现灭霸打响指英雄消失的效果 demo

热门文章

  1. 【GO语言】实现同步传输系统:局域网内手机和电脑互传文件互发消息。go语言练手项目
  2. 手把手教你两招,轻松完成图片格式转换
  3. 用python网络爬虫爬取英雄联盟英雄图片
  4. 怎样清理手机内存空间
  5. 最长公共子序列 - LCS
  6. django社交类程序笔记(14)社交模块模型创建
  7. Ubuntu桌面重命名
  8. hsbc android app,‎App Store 上的“HSBC Mobile Banking”
  9. 计算机中的表示方法,计算机应用基础第三章计算机中信息的表示方法
  10. [DDS直接数字频率合成]关于DDS技术产生调幅波的分析与思考