文章目录
1 基本概念
1.1 前言
web开发:
- web,网页的意思,www.baidu.com
- 静态web
html, css
提供给所有人看的数据始终不会发生变化 - 动态web
淘宝,几乎是所有的网站
提供给所有人看的数据始终会发生变化,每个人在不同时间,不同地点看到的信息各不相同
技术栈:Servlet/JSP, ASP, PHP
在java中,动态web资源开发的技术统称为JavaWeb
1.2 Web应用程序
web应用程序:可以提供浏览器访问的程序;
- a.html, b.html…多个web资源,这些web资源可以被外界访问,对外界提供服务;
- 能访问到的任何一个页面或资源,都存在于计算机上。
- URL
- 统一的web资源会被放在同一个文件夹下,web应用程序–>Tomcat:服务器
- 一个web应用由多部分组成(静态web,动态web)
html,css,js
jsp, servlet
java程序
jar包
配置文件(properties)
web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理;
1.3 静态web
- *.html, *.htm,这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接进行读取。
请求:浏览器地址栏输入URL,点击回车的操作叫做请求(客户端→服务器)
响应:点击回车后出现的页面叫做响应(服务器→客户端) - 静态web存在的缺点
web页面无法动态更新,所有用户看到的都是同一个页面
- 轮播图,点击特效:伪动态
- JavaScript[实际开发中应用最多]
- VBScript
无法和数据库交互——数据无法持久化,用户无法交互
1.4 动态web
页面会动态展示:“web页面的展示的效果因人而异”
WebServer 插件可以筛选安全请求,然后根据请求资源(静态动态)不同,分为两条线去寻找,最终还是将资源通过WebServer返回。
缺点:
- 加入服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序,重新发布
- 停机维护
优点:
- web页面可以动态更新,所有用户看到的都不是同一个页面
- 可以数据库交互——数据持久化,用户交互
2 web服务器
2.1 技术讲解
ASP
- 微软:国内最早流行的,
- 在HTML中嵌入了VB的脚本,ASP + COM
- 在ASP开发中,基本一个页面都有几千行业务代码,页面极其混乱
- 维护成本高
- C#
- IIS
PHP - PHP开发速度很快,功能很强大,跨平台,代码简单——70%网站都是中小型网站,开源WP
- 无法承载大访问量的情况——局限性
JSP(本质Servlet) - sun公司主推的B/S架构
- 基于Java语言的(所有的大公司,或者一些开源的组件,都是用Java写的)
- 可以承载三高问题带来的影响(高并发,高可用,高性能)
等等
2.2 web服务器
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息;
IIS
微软的;ASP;windows中自带的
Tomcat
Tomcat是Apache的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个JavaWeb初学者来说,它是最佳选择
Tomcat 实际上运行JSP 页面和Servlet。目前Tomcat最新版本为9.0。
工作3-5年之后,可以尝试手写Tomcat服务器
下载Tomcat:
1.安装or解压
2.了解配置文件以及目录结构
3.了解其作用
3 Tomcat
3.1 安装Tomcat
Tomcat官网:http://tomcat.apache.org/
下载
3.2 Tomcat的启动和配置
文件夹信息
启动Tomcat
startup.bat
可能出现的问题:
1.Java环境变量没有配置
2.闪退问题
3.乱码问题:配置文件中设置
3.3 配置
服务器核心配置文件
可以配置启动的端口号
- tomcat的默认端口号是8080
- mysql3306
- http80
- https443
<Connector port="8070" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
配置主机的名称
- 默认的主机名为localhost ->127.0.0.1
- 默认网站应用存放位置:webapps
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
面试题
请你谈一谈网站是如何进行访问的?
- 输入一个域名;点击回车
- 检查本机的C:\Windows\System32\drivers\etc\hosts.tmp配置文件下有没有这个域名的映射
- 有:直接返回对应的ip地址,地址中有我们需要访问的web程序,可以直接访问
- 无:去DNS服务器上找,找到即返回,找不到即无此域名
3.4 发布一个web网站
- 将自己写的网站放到服务器(Tomcat)中指定的web应用的文件夹下(webapps)下
- 网站结构
- webapps:Tomcat服务器的web目录
- root
- myWeb:网站的目录名
- WEB-INFO
- classes:java程序
- lib:web应用所依赖的jar包
- web.xml:网站的配置文件
- index.html:默认的首页
- static
- css
- style
- js
- img
…
4 Http
4.1 什么是Http
http(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
- 文本:html,字符串,。。。
- 超文本:图片音乐视频,定位,地图
- 端口80
Https:安全的 - 端口443
4.2 两个时代
- Http 1.0
HTTP/1.0:客户端与web服务器连接后,只能获得一个web资源,断开连接 - Http 2.0
HTTP/1.1:客户端与web服务器连接后,可以获得多个web资源
4.3 Http请求
- 客户端——发请求——服务器
百度:
Request URL: https://www.baidu.com/ 请求地址
Request Method: GET get方法/post方法
Status Code: 200 OK 状态码:200
Remote Address: 61.135.169.121:443
Accept: text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9 语言中文
Cache-Control: max-age=0
Connection: keep-alive
1.请求行
- 请求行中的请求方式:GET
- 请求方式 Get/Post,Head,Delete,Put,Tract…
get:请求能携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效
post:请求能携带的参数没有限制,大小无限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效(跟get刚好相反)
2.消息头
- Accept: 告诉浏览器,它所支持的数据类型
- Accept-Encoding: 支持哪种编码格式 GBK utf-8
- Accept-Language: 语言环境
- Cache-Control: 缓存控制
- Connection: 连接状态
- HOST:主机
4.4 Http响应
- 服务器——响应——客户端
百度:
Cache-Control: private 缓存控制
Connection: keep-alive 连接
Content-Encoding: gzip 编码类型
Content-Type: text/html;charset=utf-8
1.响应体
- Accept: 告诉浏览器,它所支持的数据类型
- Accept-Encoding: 支持哪种编码格式 GBK utf-8
- Accept-Language: 语言环境
- Cache-Control: 缓存控制
- Connection: 连接状态
- HOST:主机
- Refresh:告诉客户端,多久刷新一次
- Location:让网页重新定位
2.响应状态码
200:请求响应成功
3xx:请求重定向
你重新到我给的新位置去
4xx:找不到资源 404
资源不存在
5xx:服务器代码错误 500
502:网关错误
面试题:
当你的浏览器中地址栏输入地址并回车的一瞬间到页面能展示出来,经历了什么?
5 Maven
技术需求:
- 在JavaWeb开发中,需要使用大量jar包,手动导入
- 如何能够让一个东西自动帮我们导入和配置jar包
- 由此,Maven诞生
5.1 Maven项目架构管理工具
我们目前用来就是方便导入jar包的!
Maven的核心思想:约定大于配置
- 有约束,不要去违反
Maven会规定好你该如何去编写我们的java代码,目录结构规范
5.2 下载安装Maven
下载完成后,解压即可;
5.3 配置环境变量
配置环境变量:
- M2_HOME maven目录下的bin目录
- MAVEN_HOME maven目录
- 在系统的path中配置我们的 %MAVEN_HOME%\bin
5.4 添加阿里云镜像
作用:加速下载
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
5.5 本地仓库
建立一个仓库:localRepository
<localRepository>E:/Development_Environment/apache-maven-3.6.3/maven-repo</localRepository>
5.6 在IDEA中使用Maven
- 创建一个MavenWeb项目
包下载完成 Build Success - 观察Maven仓库中多了什么东西
- IDEA中的Maven设置
注意:
5.7 创建一个普通的Maven项目
web应用下的Maven项目
5.8 在IDEA中标记文件夹功能
标记完成
标记的另一种方式
5.9 在IDEA中配置Tomcat
解决警告问题:
我们访问一个网站,需要指定一个文件夹的名字;
这里我们访问到的Hello World!即index.jsp中的内容
5.10 pom.xml文件
pom.xml是Maven的核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--Maven的版本和头文件-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--这里就是我们刚才配置的GAV-->
<groupId>pers.dongyang</groupId>
<artifactId>javaweb-01-maven01</artifactId>
<version>1.0-SNAPSHOT</version>
<!--Package:项目的打包方式
jar:java应用
war:javaweb应用
-->
<packaging>war</packaging>
<!--可删除的模块-->
<name>javaweb-01-maven01 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<!--配置-->
<properties>
<!--项目的默认构建编码-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--编译版本-->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!--项目依赖-->
<dependencies>
<!--具体依赖的jar包配置文件-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
<!--项目构建使用的东西-->
<build>
<finalName>javaweb-01-maven01</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<!--插件-->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
jar包及其依赖的导入
Maven由于约定大于配置,我们之后可能会遇到我们写的配置文件,无法被导出或生效的问题——解决方案:
<!--在build中配置resources,来防止资源导出失败的问题-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
5.12 IDEA操作
生成目录树
5.13 解决遇到的问题
- Maven导入依赖
解决方法:使用低版本Maven依赖 - Tomcat闪退
解决方法:环境变量配置问题 - IDEA项目中每次都要重复配置Maven
解决方法:全局配置
- Maven中的Tomcat无法配置
解决方法:查看是不是使用了原来版本的Maven - Maven默认web项目中的web.xml版本问题
解决方法:
原来的:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
替换成Tomcat的webapps文件夹下的ROOT中的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"
metadata-complete="true">
<display-name>Welcome to Tomcat</display-name>
<description>
Welcome to Tomcat
</description>
</web-app>
5.14 Maven仓库的使用
初识Servlet
6 Servlet
6.1 Servlet简介
- Servlet就是sun公司开发动态web的技术
- sun公司在这些API中提供了一个接口——Servlet, 若想开发一个Servlet程序,只需完成两步
1. 编写一个类,实现Servlet接口
2.把开发好的Java类部署到web服务器中
把实现了Servlet接口的Java程序叫做Servlet
6.2 HelloServlet
servlet接口有两个默认的实现类:HttpServlet,GenericServlet
-
构建一个普通Maven项目,删掉src目录,以后我们的学习就在这个项目里面建立module;这个空的工程就叫Maven的主工程
-
关于Maven父子工程的理解
父项目中:
<modules>
<module>servlet-01</module>
</modules>
子项目中:(parent本来没有,我自己建的)
<parent>
<artifactId>javaweb-03-servlet01</artifactId>
<groupId>pers.dongyang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的jar包子项目可以直接使用
son extends father
- Maven环境优化
- 修改web.xml为最新的
- 将Maven的结构搭建完整
- 编写servlet程序
1. 编写一个普通类HelloServlet
2. 实现servlet接口,这里我们直接继承HttpServlet
/* Java
author:GrandNovice
time:2020/9/27
*/
package pers.dongyang.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet extends HttpServlet {
// 由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter(); // 响应流
writer.print("Hello, Servlet!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp); // 实现这个调用后,doGet()中的代码就不用在这里重写一遍
}
}
- 编写Servlet的映射
为什么需要映射?
写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径
<!--注册servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>pers.dongyang.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 配置Tomcat
注意项目发布路径 - 启动测试
6.3 servlet原理
servlet是由web服务器调用,web服务器在收到浏览器请求之后,会
浏览器发送Http请求给web容器,首次访问会编译出一个servlet的class(在target目录中),web容器产生两个对象——请求Request和响应Response,对象调用servlet接口中的service方法,service可以处理resp和req,service方法的具体实现由我们自己重写,request会从service拿到请求,并且把请求之后的响应交给response。
红色箭头
request发送到service,service中由我们自己实现的方法,方法执行完有一个响应,响应返回到response,最后web容器读取响应信息,响应给客户端输出。
6.4 Mapping问题
- 一个Servlet可以指定一个映射路径
<!--servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 一个Servlet可以指定多个映射路径
<!--servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello4</url-pattern>
</servlet-mapping>
- 一个Servlet可以指定通用映射路径
<!--servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
- 默认请求路径
直接跳过index主页进入请求页面
<!--servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
- 指定一些后缀或者前缀等等
<!--可以自定义后缀实现请求映射
注意:*前面不能加映射路径 /hello/*.dongyang 会报错
hello/abd/asdfgh.dongyang 正常————只要是是以*.dongyang结尾即可
测试的时候可以,写的时候不能写成前面带路径的
-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.dongyang</url-pattern>
</servlet-mapping>
- 优先级问题
指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求
<!--404-->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>pers.dongyang.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
6.5 ServletContext
6.5.1 共享数据
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用;
- 共享数据
我在这个servlet中保存的数据,可以在另一个servlet中拿到
写入
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// this.getInitParameter(); 初始化参数
// this.getServletConfig(); servlet配置
// this.getServletContext(); servlet上下文 重点
ServletContext servletContext = this.getServletContext();
String username = "信息"; // 数据
servletContext.setAttribute("username", username); // 将一个数据保存在servletContext中,名字为username,值为 "董洋"
System.out.println("Hello");
}
}
读取
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String username = (String) servletContext.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("名字" + username);
System.out.println("username = " + username); // 这里在控制台输出乱码
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
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"
metadata-complete="true">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>pers.dongyang.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getContext</servlet-name>
<servlet-class>pers.dongyang.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getContext</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
</web-app>
测试访问结果。
6.5.2 获取初始化参数
配置
<!--配置一些web应用的初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
使用
public class servletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String url = servletContext.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
6.5.3 请求转发
重定向和转发的区别
转发路径不变,重定向路径会变。
public class servletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
System.out.println("进入了ServletDemo04");
/*
RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/gp"); // 转发的请求路径
requestDispatcher.forward(req, resp); // 调用forward()方法请求转发
*/
// 上述两句可以合并为一句
servletContext.getRequestDispatcher("/gp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
6.5.4 读取资源文件
Properties
- 在java目录下新建properties——需要在该module下的pom.xml中添加代码才能正常导出.properties文件
<build>
<resources>
<!--resources目录下的properties本身就是可以导出的,
因此在这里我们注释掉对resources目录导出的限制-->
<!-- <resource>-->
<!-- <directory>src/main/resources</directory>-->
<!-- <excludes>-->
<!-- <exclude>*.properties</exclude>-->
<!-- <exclude>**/*.xml</exclude>-->
<!-- </excludes>-->
<!-- <filtering>false</filtering>-->
<!-- </resource>-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
- 在resources目录下新建properties——可以正常导出
发现都被打包到了同一个路径下:target\servlet-02-1.0-SNAPSHOT\WEB-INF\classes,我们称classes路径为类路径classpath
使用代码更改配置使得java目录中的.properties文件也能导出
思路:需要一个文件流
/* Java
author:GrandNovice
time:2020/9/27
*/
package pers.dongyang.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream resourceAsStream = this.getServletContext().
//getResourceAsStream("/WEB-INF/classes/db.properties"); // 第一个/代表servlet-02
//getResourceAsStream("/WEB-INF/classes/pers/dongyang/servlet/a.properties");
getResourceAsStream("/WEB-INF/classes/a/aa.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
//resp.setCharacterEncoding("utf-8");
resp.getWriter().print(username + ":" + password);
System.out.println("username = " + username);
System.out.println("password = " + password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
访问测试即可。
6.6 HttpServletResponse响应
web服务器接收到客户端的http请求,针对这个请求分别创建一个代表请求的HttpServletRequest对象和一个代表响应的HttpServletResponse对象;
- 如果要获取客户端请求过来的参数,找HttpServletRequest
- 如果要给客户端响应一些信息,找HttpServletResponse
6.6.1 简单分类
负责向浏览器发送数据的方法
public ServletOutputStream getOutputStream() throws IOException;
public PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
public void setCharacterEncoding(String charset);
public void setContentLength(int len);
public void setContentLengthLong(long len);
public void setContentType(String type);
public void setDateHeader(String name, long date);
public void addDateHeader(String name, long date);
public void setHeader(String name, String value);
public void addHeader(String name, String value);
public void setIntHeader(String name, int value);
public void addIntHeader(String name, int value);
public void setStatus(int sc);
响应的状态码
/**
* Status code (100) indicating the client can continue.
*/
public static final int SC_CONTINUE = 100;
/**
* Status code (101) indicating the server is switching protocols
* according to Upgrade header.
*/
public static final int SC_SWITCHING_PROTOCOLS = 101;
/**
* Status code (200) indicating the request succeeded normally.
*/
public static final int SC_OK = 200;
/**
* Status code (201) indicating the request succeeded and created
* a new resource on the server.
*/
public static final int SC_CREATED = 201;
/**
* Status code (202) indicating that a request was accepted for
* processing, but was not completed.
*/
public static final int SC_ACCEPTED = 202;
/**
* Status code (203) indicating that the meta information presented
* by the client did not originate from the server.
*/
public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
/**
* Status code (204) indicating that the request succeeded but that
* there was no new information to return.
*/
public static final int SC_NO_CONTENT = 204;
/**
* Status code (205) indicating that the agent <em>SHOULD</em> reset
* the document view which caused the request to be sent.
*/
public static final int SC_RESET_CONTENT = 205;
/**
* Status code (206) indicating that the server has fulfilled
* the partial GET request for the resource.
*/
public static final int SC_PARTIAL_CONTENT = 206;
/**
* Status code (300) indicating that the requested resource
* corresponds to any one of a set of representations, each with
* its own specific location.
*/
public static final int SC_MULTIPLE_CHOICES = 300;
/**
* Status code (301) indicating that the resource has permanently
* moved to a new location, and that future references should use a
* new URI with their requests.
*/
public static final int SC_MOVED_PERMANENTLY = 301;
/**
* Status code (302) indicating that the resource has temporarily
* moved to another location, but that future references should
* still use the original URI to access the resource.
*
* This definition is being retained for backwards compatibility.
* SC_FOUND is now the preferred definition.
*/
public static final int SC_MOVED_TEMPORARILY = 302;
/**
* Status code (302) indicating that the resource reside
* temporarily under a different URI. Since the redirection might
* be altered on occasion, the client should continue to use the
* Request-URI for future requests.(HTTP/1.1) To represent the
* status code (302), it is recommended to use this variable.
*/
public static final int SC_FOUND = 302;
/**
* Status code (303) indicating that the response to the request
* can be found under a different URI.
*/
public static final int SC_SEE_OTHER = 303;
/**
* Status code (304) indicating that a conditional GET operation
* found that the resource was available and not modified.
*/
public static final int SC_NOT_MODIFIED = 304;
/**
* Status code (305) indicating that the requested resource
* <em>MUST</em> be accessed through the proxy given by the
* <code><em>Location</em></code> field.
*/
public static final int SC_USE_PROXY = 305;
/**
* Status code (307) indicating that the requested resource
* resides temporarily under a different URI. The temporary URI
* <em>SHOULD</em> be given by the <code><em>Location</em></code>
* field in the response.
*/
public static final int SC_TEMPORARY_REDIRECT = 307;
/**
* Status code (400) indicating the request sent by the client was
* syntactically incorrect.
*/
public static final int SC_BAD_REQUEST = 400;
/**
* Status code (401) indicating that the request requires HTTP
* authentication.
*/
public static final int SC_UNAUTHORIZED = 401;
/**
* Status code (402) reserved for future use.
*/
public static final int SC_PAYMENT_REQUIRED = 402;
/**
* Status code (403) indicating the server understood the request
* but refused to fulfill it.
*/
public static final int SC_FORBIDDEN = 403;
/**
* Status code (404) indicating that the requested resource is not
* available.
*/
public static final int SC_NOT_FOUND = 404;
/**
* Status code (405) indicating that the method specified in the
* <code><em>Request-Line</em></code> is not allowed for the resource
* identified by the <code><em>Request-URI</em></code>.
*/
public static final int SC_METHOD_NOT_ALLOWED = 405;
/**
* Status code (406) indicating that the resource identified by the
* request is only capable of generating response entities which have
* content characteristics not acceptable according to the accept
* headers sent in the request.
*/
public static final int SC_NOT_ACCEPTABLE = 406;
/**
* Status code (407) indicating that the client <em>MUST</em> first
* authenticate itself with the proxy.
*/
public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
/**
* Status code (408) indicating that the client did not produce a
* request within the time that the server was prepared to wait.
*/
public static final int SC_REQUEST_TIMEOUT = 408;
/**
* Status code (409) indicating that the request could not be
* completed due to a conflict with the current state of the
* resource.
*/
public static final int SC_CONFLICT = 409;
/**
* Status code (410) indicating that the resource is no longer
* available at the server and no forwarding address is known.
* This condition <em>SHOULD</em> be considered permanent.
*/
public static final int SC_GONE = 410;
/**
* Status code (411) indicating that the request cannot be handled
* without a defined <code><em>Content-Length</em></code>.
*/
public static final int SC_LENGTH_REQUIRED = 411;
/**
* Status code (412) indicating that the precondition given in one
* or more of the request-header fields evaluated to false when it
* was tested on the server.
*/
public static final int SC_PRECONDITION_FAILED = 412;
/**
* Status code (413) indicating that the server is refusing to process
* the request because the request entity is larger than the server is
* willing or able to process.
*/
public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
/**
* Status code (414) indicating that the server is refusing to service
* the request because the <code><em>Request-URI</em></code> is longer
* than the server is willing to interpret.
*/
public static final int SC_REQUEST_URI_TOO_LONG = 414;
/**
* Status code (415) indicating that the server is refusing to service
* the request because the entity of the request is in a format not
* supported by the requested resource for the requested method.
*/
public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
/**
* Status code (416) indicating that the server cannot serve the
* requested byte range.
*/
public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
/**
* Status code (417) indicating that the server could not meet the
* expectation given in the Expect request header.
*/
public static final int SC_EXPECTATION_FAILED = 417;
/**
* Status code (500) indicating an error inside the HTTP server
* which prevented it from fulfilling the request.
*/
public static final int SC_INTERNAL_SERVER_ERROR = 500;
/**
* Status code (501) indicating the HTTP server does not support
* the functionality needed to fulfill the request.
*/
public static final int SC_NOT_IMPLEMENTED = 501;
/**
* Status code (502) indicating that the HTTP server received an
* invalid response from a server it consulted when acting as a
* proxy or gateway.
*/
public static final int SC_BAD_GATEWAY = 502;
/**
* Status code (503) indicating that the HTTP server is
* temporarily overloaded, and unable to handle the request.
*/
public static final int SC_SERVICE_UNAVAILABLE = 503;
/**
* Status code (504) indicating that the server did not receive
* a timely response from the upstream server while acting as
* a gateway or proxy.
*/
public static final int SC_GATEWAY_TIMEOUT = 504;
/**
* Status code (505) indicating that the server does not support
* or refuses to support the HTTP protocol version that was used
* in the request message.
*/
public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
6.6.2 下载文件
- 向浏览器输出消息(前面已讲)
- 下载/上传文件
1. 要获取下载文件的路径
2. 下载的文件名
3. 先办法让浏览器能够支持下载我们所需的东西
4. 获取下载文件的输入流
5. 创建缓冲区
6. 获取OutputStream对象
7. 将FileOutputStream流写入到buffer缓冲区
8. 使用OutputStream将缓冲区中的数据输出到客户端
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
1. 要获取下载文件的路径
2. 下载的文件名
3. 先办法让浏览器能够支持下载我们所需的东西
4. 获取下载文件的输入流
5. 创建缓冲区
6. 获取OutputStream对象
7. 将FileOutputStream流写入到buffer缓冲区
8. 使用OutputStream将缓冲区中的数据输出到客户端
*/
// 1. 要获取下载文件的路径
String realPath = "E:\\IDEA_project\\JavaWeb\\javaweb-03-servlet01\\response\\target\\classes\\dog.jpg";
System.out.println("realPath = " + realPath);
// 2. 下载的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
// 3. 先办法让浏览器能够支持Content-Disposition下载我们所需的东西
// 下载文件为中文命名时,需要使用URLEncoder.encode(fileName, "utf-8") 进行编码,否则会出现下载的文件名乱码
resp.setHeader("Content-Disposition", "attachment; filename" + URLEncoder.encode(fileName, "utf-8"));
// 4. 获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
// 5. 创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];
// 6. 获取OutputStream对象
ServletOutputStream out = resp.getOutputStream();
// 7. 将FileOutputStream流写入到buffer缓冲区 8. 使用OutputStream将缓冲区中的数据输出到客户端
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6.6.3 验证码功能
验证码怎么来的?
- 前端实现
- 后端实现(需要用到java的图片类,生成一个图片 )
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 如何让浏览器每1秒自动刷新一次
resp.setHeader("refresh", "1");
// 在内存中创建图片
BufferedImage image = new BufferedImage(80, 60, BufferedImage.TYPE_INT_RGB);
// 操作图片
Graphics2D graphics = (Graphics2D) image.getGraphics(); // 定义一只画笔
// 设置图片背景颜色
graphics.setColor(Color.white);
// 填充背景颜色,从(0, 0)点到(80, 60)点
graphics.fillRect(0, 0, 80, 60);
// 给图片写数据
graphics.setColor(Color.blue);
graphics.setFont(new Font(null, Font.BOLD, 20));
graphics.drawString(generateRandomNumber(), 20, 35);
// 告诉浏览器这个请求用图片的方式打开
resp.setContentType("image/jpg");
// 网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires", -1); // expires=-1表示不会被浏览器缓存
resp.setHeader("Cache-Control", "no-cache"); // 告诉浏览器缓存策略为不缓存
resp.setHeader("Pragma", "no-cache");
// 把图片写给浏览器
ImageIO.write(image, "jpg", resp.getOutputStream());
}
// 生成随机数
private String generateRandomNumber() {
Random random = new Random();
String randomNumber = random.nextInt(9999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 4 - randomNumber.length(); i++) {
sb.append("0");
}
String string = sb.toString() + randomNumber;
return string;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6.6.4 实现重定向
一个web资源收到客户端请求后,它会通知客户端去访问另外一个web资源,这个过程叫重定向。
常见场景:
- 用户登录
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
// 重定向可以拆分为一下两步
resp.setHeader("Location", "/response_war/image");
resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
// resp.setStatus(302); //这句代码等于上一句
*/
// 重定向
resp.sendRedirect("/response_war/image");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
面试题:
重定向和转发的区别?
相同:
- 页面都会实现跳转
不同:
- 请求转发的时候,URL不会发生变化 Http状态码:307
- 重定向的时候,URL会发生变化 Http状态码:302
6.7 HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,我们可以获得客户端的所有信息。
6.7.1 获取前端传递的参数
6.7.2 请求转发
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 后台接收以及浏览器输出中文乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println("===============================");
System.out.println("username = " + username);
System.out.println("password = " + password);
System.out.println(Arrays.toString(hobbys));
System.out.println("===============================");
// 通过请求转发
// 这里的 / 代表当前的web应用
req.getRequestDispatcher("/success.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
7 Session和Cookie
7.1 会话
会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程称为一次会话。
有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾经来过,这个过程称为有状态会话。
你怎么证明你是学校的学生?
- 学费发票 学校给你发票
- 学校学籍 学校标记你来过了
一个网站怎么证明你来过?
服务端怎么证明客户端已经来过了?
- 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了;cookie
- 服务器登记你来过了,下次你来的时候我来匹配你;session
7.2 保存会话的两种技术
cookie
- 客户端技术 (响应,请求)
session
- 服务器技术,利用这个技术可以保存用户的会话信息。我们可以把信息或数据放在session中!
常见场景:
网站登录账户后,下次登录不用再输入用户名和密码,可以直接登录上去。
7.3 Cookie
第一次访问网站,服务器给客户端发送一个Cookie,请求的时候携带Cookie
- 从请求中拿到cookie信息
- 服务器响应给客户端cookie
// 保存用户上一次访问的时间
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 服务器告诉你,你来的时间,把这个时间封装成为一个信件,你下次带来,我就知道你来了
// 解决中文乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
// 创建输出对象
PrintWriter out = resp.getWriter();
// Cookie服务器端从客户端获取
Cookie[] cookies = req.getCookies(); // 这里返回数组,说明Cookie可能存在多个
// 判断Cookie是否存在
if (cookies != null) {
// 如果存在怎么办
// 遍历数组
out.write("你上一次访问的时间是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
// 获取cookie的名字
if (cookie.getName().equals("lastLoginTime")) {
// 获取cookie中的值
String value = cookie.getValue();
// 解析成长整型数值,方便下一步转换成时间
long lastLoginTime = Long.parseLong(value);
Date date = new Date(lastLoginTime);
out.write(date.toLocaleString());
}
}
} else {
out.write("这是您第一次访问本站!");
}
// 服务器给客户端响应一个Cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
// cookie有效期为一天
cookie.setMaxAge(24*60*60);
// 响应给客户端一个cookie
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
cookie一般会保存在本地的用户目录下appdata;
一个网站的cookie是否存在上限?
- 一个cookie只能保存一个信息
- 一个web站点可以给浏览器发送多个cookie,每个站点最多存放20个cookie
- 浏览器cookie上限大概为300个
- cookie大小有限制
删除cookie
- 不设置有效期,关闭浏览器,自动失效
- 设置有效期时间为0
// 保存用户上一次访问的时间
public class CookieDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 创建一个cookie,名字跟要删除的一致
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
// 将cookie有效期设置为0
cookie.setMaxAge(0);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
编码解码
// 中文数据传递
public class CookieDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决中文乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
// Cookie服务器端从客户端获取
Cookie[] cookies = req.getCookies(); // 这里返回数组,说明Cookie可能存在多个
PrintWriter out = resp.getWriter();
// 判断Cookie是否存在
if (cookies != null) {
// 如果存在怎么办
// 遍历数组
out.write("你上一次访问的时间是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
// 获取cookie的名字
if (cookie.getName().equals("name")) {
// System.out.println(cookie.getValue());
// 解码
out.write(URLDecoder.decode(cookie.getValue(), "utf-8"));
}
}
} else {
out.write("这是您第一次访问本站!");
}
Cookie cookie = new Cookie("name", URLEncoder.encode("冬阳", "utf-8")); // 编码
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
7.4 Session(重点)
什么是Session?
- 服务器会给每一个用户(浏览器)创建一个Session对象
- 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就一直存在
- 用户登录之后,整个网站它都可以访问 (Session应用,保存用户信息,保存购物车信息)
Session和Cookie的区别
- Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
- Session是把用户的数据写到用户独占的Session中,服务器端保存(保存重要信息,减少服务器资源的浪费)
- Session对象由服务器创建
使用场景:
- 保存一个登录用户的信息
- 购物车信息
- 在整个网站中经常会使用的数据,我们将它保存在Session中
使用Session
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 得到Session
HttpSession session = req.getSession();
// 给Session中存入东西
// session.setAttribute("name", "冬阳");
session.setAttribute("name", new Person("冬阳", 18));
// 获取Session的id
String sessionId = session.getId();
// 判断Session是不是新创建的
if (session.isNew()) {
resp.getWriter().write("Session创建成功,SessionID为: " + sessionId);
} else {
resp.getWriter().write("Session已经在服务器中存在了, SessionID为: " + sessionId);
}
// Session创建的时候做了什么事情
/*
Cookie cookie = new Cookie("JSESSIONID", sessionId);
resp.addCookie(cookie);
*/
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决乱码问题
resp.setCharacterEncoding("utf-8");
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 得到Session
HttpSession session = req.getSession();
Person person = (Person) session.getAttribute("name");
System.out.println(person.toString());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
public class SessionDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
// 从此session中删除与指定名称绑定的对象。 如果session没有与指定名称绑定的对象,则此方法不执行任何操作。
session.removeAttribute("name");
// 使该session无效,然后取消绑定到该session的任何对象。手动注销Session
session.invalidate();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
xml配置Session自动过期
<!--设置Session默认的失效时间-->
<session-config>
<!--1分钟后Session自动失效(以分钟为单位)-->
<session-timeout>1</session-timeout>
</session-config>
shift + tab 可以取消缩进
8 JSP
8.1 什么是JSP
Java Server Pages:Java服务器端页面,也和servlet一样,用于动态web技术。
特点:
- 写JSP就像在写HTML
- 区别:
- Html只给用户提供静态的数据
- JSP页面中可以嵌入JAVA代码,为用户提供动态数据
8.2 JSP原理
思路:JSP到底怎么执行?查看target
- 代码层面没有任何问题
- 服务器内部工作
- Tomcat中有一个work目录;
- IDEA中使用Tomcat的话,会在IDEA的Tomcat中生成一个work目录
本机地址:
C:\Users\dongy\.IntelliJIdea2019.2\system\tomcat\Unnamed_javaweb-session-cookie\work\Catalina\localhost\ROOT\org\apache\jsp
发现页面转变成了Java程序!
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问servlet
JSP最终也会被转换成为一个Java类!
JSP本质上就是一个servlet!
// 初始化
public void _jspInit() {
}
// 销毁
public void _jspDestroy() {
}
// JSPservice
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response){
}
- 判断请求
- 内置一些对象
final javax.servlet.jsp.PageContext pageContext; // 页面上下文
javax.servlet.http.HttpSession session = null; // session
final javax.servlet.ServletContext application; // applicationContext
final javax.servlet.ServletConfig config; // config
javax.servlet.jsp.JspWriter out = null; // out
final java.lang.Object page = this; // page 当前
HttpServletRequest request; // 请求
HttpServletResponse response; // 响应
- 输出页面前增加的代码
response.setContentType("text/html"); // 设置响应的页面类型
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
- 以上的这些对象,我们可以在jsp页面中直接使用
在JSP页面中,Java代码原封不动输出, Html代码会被转换,然后渲染到前端
out.write(" <title>Title</title>\r\n");
8.3 JSP的基础语法
任何语言都有自己的语法!
JSP作为Java技术的一种应用,它拥有自己扩充的语法,Java所有语法都支持!
JSP表达式
<%--注释符号不同--%>
<%--JSP表达式 <%= 变量/表达式%>
作用:将程序的结果输出到客户端
--%>
<%=new java.util.Date()%>
JSP脚本片段
<%--JSP脚本片段--%>
<%
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
out.println("<h1>sum=" + sum + "<h1>");
%>
脚本片段的再实现
<%
int x = 10;
out.println(x);
%>
<p>这是一个JSP文档</p>
<%
int y = 20; // x不可重复定义
out.println(x);
%>
<hr>
<%--在代码中嵌入html元素--%>
<%
for (int i = 0; i < 5; i++) {
%>
<h1>HelloWorld <%=i%></h1>
<%
}
%>
JSP声明
<%--可以定义在方法_jspService()外,类index_jsp内--%>
<%!
static {
System.out.println("Loading Servlet");
}
private int globalVar = 0;
public void method() {
System.out.println("进入了方法method()");
}
%>
JSP声明会被编译到JSP生成的Java类中!其他的会被编译到方法_jspService()内
在JSP中嵌入Java代码即可
<%%>
<%=%>
<%!%>
<%--注释--%>
JSP的注释不会再客户端代码查看显示,HTML注释会!
8.4 JSP指令
<%--定制错误页面--%>
<%@page errorPage="error/500.jsp" %>
<%--提取公共页面--%>
<%@include file=""%>
<%--
Created by IntelliJ IDEA.
User: dongy
Date: 2020/10/5
Time: 16:44
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--@include会将两个页面合二为一--%>
<%@include file="common/header.jsp"%>
<h1>网页主体</h1>
<%--
<%
int i = 10; // 重复定义变量i,会在运行时报错
%>
--%>
<%@include file="common/footer.jsp"%>
<hr>
<%--jsp标签--%>
<%--jsp:include会拼接页面,本质还是三个页面,这种方式灵活性更高--%>
<jsp:include page="common/header.jsp"/>
<h1>网页主体</h1>
<%
int i = 10; // 不同页面分别定义变量i,不会报错
%>
<jsp:include page="common/footer.jsp"/>
</body>
</html>
8.5 九大内置对象
- PageContext 存东西
- Request 存东西
- Response
- Session 存东西
- Application [ServletContext] 存东西
- config [ServletConfig]
- out
- page 几乎不用
- exception
pageContext.setAttribute("name1", "冬阳1号"); // 保存的数据只在一个页面中有效
request.setAttribute("name2", "冬阳2号"); // 保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3", "冬阳3号"); // 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4", "冬阳4号"); // 保存的数据在服务器中有效,从打开服务器到关闭服务器
request:客户端向服务器发送请求产生的数据,用户看完就没用了,比如,新闻等
session:客户端向服务器发送请求产生的数据,用户用完一会还有用,比如,购物车
application:客户端向服务器发送请求产生的数据,一个用户用完了,其他用户还可能使用,比如,聊天数据
8.6 JSP标签、JSTL标签、EL表达式
EL表达式:${}
- 获取数据
- 执行运算
- 获取web开发的常用对象
调用java方法
<!--jstl表达式依赖-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!--standard标签库依赖-->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
JSP标签
%--
http://localhost:8080/jsptag.jsp?name=dongyang&age=12
--%>
<jsp:forward page="jsptag2.jsp">
<jsp:param name="name" value="dongyang"></jsp:param>
<jsp:param name="age" value="12"></jsp:param>
</jsp:forward>
JSTL表达式
JSTL标签库的使用是为了弥补HTML标签的不足
它自定义了许多标签,可以供我们使用,标签的功能和Java代码一样
- 核心标签
JSTL标签库使用步骤
1. 引入对应的taglib
2. 使用其中的方法
3. 在Tomcat中也需要引入jstl的包,否则会报错:JSTL解析错误
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入jstl核心标签库,我们才能使用jstl标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h4>if测试</h4>
<hr>
<form action="coreif.jsp" method="get">
<%--EL表达式获取表单中的数据value="${param.参数名}"--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断如果提交的用户名是管理员则登录成功--%>
<%--
<%
if (request.getParameter("username").equals("admin")) {
out.println("登录成功");
}
%>
--%>
<c:if test="${param.username=='admin'}" var="isAdmin">
<c:out value="管理员欢迎您!"></c:out>
</c:if>
<c:out value="${isAdmin}"></c:out>
</body>
</html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--定义一个变量score,值为85--%>
<c:set var="score" value="95"></c:set>
<c:choose>
<c:when test="${score>=90}">
优秀
</c:when>
<c:when test="${score>=80}">
良好
</c:when>
<c:when test="${score>=70}">
一般
</c:when>
<c:when test="${score>=60}">
一般般
</c:when>
<c:when test="${score<60}">
差
</c:when>
</c:choose>
</body>
</html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
ArrayList<String> people = new ArrayList<>();
people.add(0, "张三");
people.add(1, "李四");
people.add(2, "王五");
people.add(3, "赵六");
people.add(4, "田七");
request.setAttribute("list", people);
%>
<%--
var:每一次遍历出来的变量
items:要遍历的容器对象(可迭代)
begin:开始
end:结束
step:步长
--%>
<c:forEach var="people" items="${list}">
<c:out value="${people}"></c:out> <br>
</c:forEach>
<hr>
<c:forEach var="people" items="${list}" begin="1" end="3" step="2">
<c:out value="${people}"></c:out> <br>
</c:forEach>
</body>
</html>
-
格式化标签
-
SQL标签
-
XML标签
9 JavaBean
实体类
JavaBean有特定的写法:
- 一个无参构造
- 属性必须私有化
- 必须有对应的get/set方法
一般用来和数据库的字段做映射。ORM;
ORM:对象关系映射
- 数据库中的表——Java中的类
- 字段——属性
- 行记录——对象
people表
id | name | age | address |
---|---|---|---|
1 | 冬阳1号 | 16 | 山西 |
2 | 冬阳2号 | 17 | 山东 |
3 | 冬阳3号 | 18 | 山南 |
class People{
private int id;
private String name;
private int age;
private String address;
}
class A {
new People(1, "冬阳1", 3, "西安");
new People(2, "冬阳2", 5, "西安");
new People(3, "冬阳3", 6, "西安")
}
10 MVC三层架构
什么是MVC?
Model View Controller 模型、视图和控制器
10.1 早期架构
用户直接访问控制层,控制层就可以直接操作数据库。
servlet -> 增删改查 -> 数据库
弊端:JDBC代码要写道servlet的处理请求中,程序臃肿,不利于维护
servlet的代码中:处理请求,响应,视图跳转,处理JDBC,处理业务代码,处理逻辑代码
架构:没有什么是加一层解决不了的
JDBC
MySQL Oracle SqlServer
10.2 MVC三层架构
Model:
- 业务处理:业务逻辑(Service)
- 数据持久层:CRUD增删改查(Dao)
View:
- 展示数据
- 提供链接发起Servlet请求(a, form, herf, …)
Controller:(Servlet)
- 接收用户的请求(Request请求参数、Session信息,…)
- 交给业务层处理对应的代码
- 控制视图跳转
登录 ---> 接收用户的登录请求 ---> 处理用户的请求(获取用户登录的参数username,password) ---> 交给业务层处理登录业务(判断用户名密码是否正确,事务) ---> Dao层查询用户名和密码是否正确 ---> 数据库
11 Filter
Filter:过滤器,用来过滤网站的数据;
应用场景:
- 处理中文乱码
- 登录验证
- …
Filter开发步骤:
- 导包
- 编写过滤器
实现Filter接口,重写三个方法
/* Java
author:GrandNovice
time:2020/10/5
*/
package pers.dongyang.filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
// 初始化:web服务器启动的同时初始化,随时等待过滤对象出现
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter已经初始化");
}
// chain 链
/**
* 1.过滤器中的所有代码在过滤特定请求的时候都会执行
* 2.必须要让过滤器继续通行
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
System.out.println("CharacterEncodingFilter执行前");
// 让我们的请求继续执行,如果不写,程序在这里被拦截停止
chain.doFilter(request, response);
System.out.println("CharacterEncodingFilter执行后");
}
// 销毁:web服务器关闭的时候过滤器会销毁
public void destroy() {
System.out.println("CharacterEncodingFilter已经销毁");
}
}
- 在web.xml中配置Filter
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>pers.dongyang.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--只要是/servlet下的任何请求都会经过这个过滤器-->
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
12 监听器
实习一个监听器的接口(有n种):
- 编写一个监听器
实现监听器的接口
package pers.dongyang.listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
// 统计网站在线人数:实际是统计session
public class OnlineCountListener implements HttpSessionListener {
// 创建session监听
// session创建一次,触发一次这个事件
public void sessionCreated(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
System.out.println(se.getSession().getId());
Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount == null) {
onlineCount = new Integer(1);
} else {
int count = onlineCount.intValue();
onlineCount = new Integer(count + 1);
}
ctx.setAttribute("OnlineCount", onlineCount);
}
// 销毁session监听
// session销毁一次,触发一次这个事件
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext ctx = se.getSession().getServletContext();
Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
if (onlineCount == null) {
onlineCount = new Integer(0);
} else {
int count = onlineCount.intValue();
onlineCount = new Integer(count - 1);
}
ctx.setAttribute("OnlineCount", onlineCount);
}
/**
* Session销毁的两种情况:
* 1. 手动销毁 se.getSession().invalidate();
* 2. 自动销毁 web.xml配置
* <!--自动销毁session-->
* <session-config>
* <!--以分钟为单位-->
* <session-timeout>1</session-timeout>
* </session-config>
*/
}
- 在web.xml中配置监听器
<!--注册监听器-->
<listener>
<listener-class>pers.dongyang.listener.OnlineCountListener</listener-class>
</listener>
- 看情况选择使用
13 过滤器监听器常见应用
监听器:GUI编程中常用
package pers.dongyang.listener;
import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class TestPanel {
public static void main(String[] args) {
Frame frame = new Frame("中秋节快乐"); // 新建一个窗体
Panel panel = new Panel(null); // 面板
frame.setLayout(null); // 设置窗体的布局
frame.setBounds(300, 300, 500, 500);
frame.setBackground(new Color(0, 0, 255)); // 设置背景颜色
panel.setBounds(50, 50, 300, 300); //
panel.setBackground(new Color(0, 255, 0)); //
frame.add(panel);
frame.setVisible(true);
// 监听事件,监听关闭事件
frame.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {
System.out.println("打开");
}
public void windowClosing(WindowEvent e) {
System.out.println("关闭ing");
System.exit(0);
/*
* System.exit(0);和System.exit(1);区别
* 正常终止和非正常终止
*
* System.exit(0) : 将整个虚拟机里的内容都关掉,内存都释放掉!正常退出程序。
* System.exit(1) : 非正常退出程序
* System.exit(-1) :非正常退出程序
* */
}
public void windowClosed(WindowEvent e) {
System.out.println("关闭ed");
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
System.out.println("激活");
}
public void windowDeactivated(WindowEvent e) {
System.out.println("未激活");
}
});
}
}
用户登录之后才能进入主页,用户注销后就不能进入主页了!
- 用户登录后向Session中放入用户数据
- 进入主页时要判断用户是否已经登录,要求在过滤器中实现,在页面中实现会报错
过滤器
package pers.dongyang.filter;
import pers.dongyang.util.Constant;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SysFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
if (request.getSession().getAttribute(Constant.USER_SESSION)==null) {
response.sendRedirect("/error.jsp");
}
filterChain.doFilter(req, resp);
}
public void destroy() {
}
}
登录实现
package pers.dongyang.servlet;
import pers.dongyang.util.Constant;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取前端请求的参数
String username = req.getParameter("username");
if (username.equals("admin")) {
// 登录成功
req.getSession().setAttribute(Constant.USER_SESSION, req.getSession().getId());
resp.sendRedirect("/sys/success.jsp");
}else {
// 登录失败
resp.sendRedirect("/error.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
登录页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录 </h1>
<form action="/servlet/login" method="post">
<input type="text" name="username">
<input type="submit">
</form>
</body>
</html>
主页
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>主页</h1>
<p><a href="/servlet/logout">注销</a></p>
</body>
</html>
注销实现
package pers.dongyang.servlet;
import pers.dongyang.util.Constant;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object user_session = req.getSession().getAttribute(Constant.USER_SESSION); // 属性没了,session还在
if (user_session!=null) {
req.getSession().removeAttribute(Constant.USER_SESSION);
resp.sendRedirect("/Login.jsp");
}else {
resp.sendRedirect("/Login.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Session常量
/* Java
author:GrandNovice
time:2020/10/6
*/
package pers.dongyang.util;
public class Constant {
public final static String USER_SESSION = "USER_SESSION";
}
错误页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>错误页面</h1>
<p><a href="/Login.jsp">返回登录页面</a></p>
</body>
</html>
web.xml
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>pers.dongyang.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/servlet/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>pers.dongyang.servlet.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/servlet/logout</url-pattern>
</servlet-mapping>
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>pers.dongyang.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
扩展:VIP123页面划分
14 JDBC
什么是JDBC?
Java DataBase Connectivity
需要jar包支持
- java.sql
- javax.sql
- mysql-connector-java…
实验环境搭建
CREATE TABLE users(
id INT PRIMARY KEY,
`name` VARCHAR(40),
`password` VARCHAR(40),
`email` VARCHAR(60),
`birthday` DATE
);
INSERT INTO `users`(`id`, `name`, `password`, `email`, `birthday`)
VALUES(1, '张三', '123456', 'zs@qq.com', '2000-01-01');
INSERT INTO `users`(`id`, `name`, `password`, `email`, `birthday`)
VALUES(2, '李四', '123456', 'ls@qq.com', '2000-01-01');
INSERT INTO `users`(`id`, `name`, `password`, `email`, `birthday`)
VALUES(3, '王五', '123456', 'ww@qq.com', '2000-01-01');
SELECT * FROM `users`;
导入数据库依赖
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
IDEA中连接
JDBC固定步骤:
- 加载驱动
- 连接数据库
- 向数据库发送SQL的对象Statement 做CRUD
- 编写SQL
- 执行(查询)SQL,(返回ResultSet结果集)
- 关闭连接,释放资源(必须做) 先开后关
public class TestJDBC {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 配置信息
// useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
// 1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库,代表数据库对象
Connection connection = DriverManager.getConnection(url, username, password);
// 3.向数据库发送SQL的对象Statement 做CRUD
Statement statement = connection.createStatement();
// 4.编写SQL
String sql = "select * from users";
// 5.执行(查询)SQL,(返回ResultSet结果集)
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println("id="+ resultSet.getObject("id"));
System.out.println("name="+ resultSet.getObject("name"));
System.out.println("password="+ resultSet.getObject("password"));
System.out.println("email="+ resultSet.getObject("email"));
System.out.println("birthday="+ resultSet.getObject("birthday"));
}
// 6.关闭连接,释放资源(必须做) 先开后关
resultSet.close();
statement.close();
connection.close();
}
}
详细查看MySQL
事务
要么都成功,要么都失败!
ACID原则:保证数据安全
- 开启事务
- 事务提交 commit()
- 事务回滚 rollback()
- 关闭事务
Junit单元测试
依赖
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
@Test注解只有在方法上有效,只要加了这个注解的方法,就可以直接运行!
@Test
public void test01() {
System.out.println("hello");
}
成功
失败
搭建一个环境
@Test
public void test03() throws Exception {
// 配置信息
// useUnicode=true&characterEncoding=utf-8 解决中文乱码
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";
Connection connection = null;
// 1.加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
// 2.连接数据库,代表数据库对象
connection = DriverManager.getConnection(url, username, password);
// 3.通知数据库开启事务
connection.setAutoCommit(false); // 关闭自动提交,即开启事务
String sql1 = "update account\n" +
"set money = money - 100\n" +
"where name = 'a';";
connection.prepareStatement(sql1).executeUpdate();
// 制造错误
// int i = 1/0;
String sql2 = "update account\n" +
"set money = money + 100\n" +
"where name = 'b';";
connection.prepareStatement(sql2).executeUpdate();
connection.commit(); // 以上两条SQL都执行成功了就提交事务
System.out.println("提交成功");
}catch (Exception e) {
try {
// 如果出现异常,就通知数据库回滚事务
connection.rollback();
}catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
connection.close();
}
}
15 SMBMS超市订单管理系统
数据库:
项目如何搭建?
考虑是否使用Maven?依赖还是导jar包
15.1 项目搭建准备工作(八步)
-
搭建一个MavenWeb项目
-
配置Tomcat
-
测试项目是否能够运行
-
导入项目中会依赖的jar包 jsp servlet mysql驱动 jstl standard
-
创建项目包结构
dao:data access object:数据访问对象,主要做的事情就是对数据库单表进行增删改操作,查的有可能是多表管理查询
service: 对应界面上的操作,增删改查,至于这个业务涉及到几个dao,就调用几个dao
servlet:
1、接受用户请求,进行处理(doget/dopost)调用service,得到数据
2、做出响应(HTML):通过PrintWriter out = response.getWriter();通过out输出 HTML代码业务流程:
一个业务都是从后到前,第一步:设计数据库
dao-service(调用多个dao)-servlet(接受用户请求,做出响应)--------HTML(JSP技术)
-
编写实体类
ORM映射:数据库中的表和pojo包中的实体类映射 -
编写基础公共类
1. 数据库配置文件
2. 编写数据库的公共类
package pers.dongyang.dao;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
// 操作数据库的公共类
public class BaseDao {
private static String driver;
private static String url;
private static String username;
private static String password;
// 静态代码块,在类加载的时候初始化
static {
Properties properties = new Properties();
// 通过类加载器读取对应的资源
InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}
//获取数据库连接
public static Connection getConnection() {
Connection connection = null;
try {
Class.forName(driver);
connection = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
// 编写查询公共类
public static ResultSet execute(Connection connection, String sql, Object[] params, ResultSet resultSet, PreparedStatement preparedStatement) throws SQLException {
// 获得连接,预编译sql
preparedStatement = connection.prepareStatement(sql);
// 传递参数
for (int i = 0; i < params.length; i++) {
// setObject占位符从1开始,但是我们的数组是从0开始
preparedStatement.setObject(i + 1, params[i]);
}
resultSet = preparedStatement.executeQuery();
return resultSet;
}
// 编写增删改公共方法
public static int execute(Connection connection, String sql, Object[] params, PreparedStatement preparedStatement) throws SQLException {
// 获得连接
preparedStatement = connection.prepareStatement(sql);
// 传递参数
for (int i = 0; i < params.length; i++) {
// setObject占位符从1开始,但是我们的数组是从0开始
preparedStatement.setObject(i + 1, params[i]);
}
int updateRows = preparedStatement.executeUpdate();
return updateRows;
}
// 释放资源
public static boolean closeResource(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
boolean flag = true;
if (resultSet != null) {
try {
resultSet.close();
// GC回收
resultSet = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
if (connection != null) {
try {
connection.close();
// GC回收
connection = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
// GC回收
preparedStatement = null;
} catch (SQLException e) {
e.printStackTrace();
flag = false;
}
}
return flag;
}
}
3.编写字符编码过滤器
package pers.dongyang.filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
chain.doFilter(request,response);
}
public void destroy() {
}
}
注册
<!--注册字符编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>pers.dongyang.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 导入静态资源
15.2 登录功能实现
- 编写前端页面
- 设置首页
<!--设置首页-->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
- 编写dao层得到用户登录的接口
package pers.dongyang.dao.user;
import pers.dongyang.pojo.User;
import java.sql.Connection;
public interface UserDao {
// 得到要登录的用户
public User getLoginUser(Connection connection, String userCode) throws Exception;
}
- 编写dao接口的实现类
public class UserDaoImpl implements UserDao {
public User getLoginUser(Connection connection, String userCode) throws Exception {
PreparedStatement pstm = null;
ResultSet rs = null;
User user = null;
if (connection !=null) {
String sql = "select * from smbms_user where userCode=?";
Object[] params = {userCode};
rs = BaseDao.execute(connection, pstm, rs, sql, params);
if (rs.next()) {
user = new User();
user.setId(rs.getInt("id"));
user.setUserCode(rs.getString("userCode"));
user.setUserName(rs.getString("userName"));
user.setUserPassword(rs.getString("userPassword"));
user.setGender(rs.getInt("gender"));
user.setBirthday(rs.getDate("birthday"));
user.setPhone(rs.getString("phone"));
user.setAddress(rs.getString("address"));
user.setUserRole(rs.getInt("userRole"));
user.setCreatedBy(rs.getInt("createdBy"));
user.setCreationDate(rs.getTimestamp("creationDate"));
user.setModifyBy(rs.getInt("modifyBy"));
user.setModifyDate(rs.getTimestamp("modifyDate"));
}
BaseDao.closeResource(null, pstm, rs);
}
return user;
}
}
- 业务层接口
public interface UserService {
// 用户登录
public User login(String userCode, String password);
}
- 业务层实现类
public class UserServiceImpl implements UserService {
// 业务层都会调用dao层,所以我们要引入dao层
private UserDao userDao;
public UserServiceImpl() {
userDao = new UserDaoImpl();
}
public User login(String userCode, String password) {
Connection connection = null;
User user = null;
try {
connection = BaseDao.getConnection();
// 通过业务层调用对应的具体的数据库操作
user = userDao.getLoginUser(connection, userCode);
} catch (Exception e) {
e.printStackTrace();
} finally {
BaseDao.closeResource(connection, null, null);
}
return user;
}
/*
@Test
public void test01() {
UserServiceImpl userService = new UserServiceImpl();
User admin = userService.login("admin", "1234567");
System.out.println(admin.getUserPassword());
}
*/
}
- 编写servlet
public class LoginServlet extends HttpServlet {
// Servlet:控制层,调用业务层代码
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("LoginServlet start...");
// 获取用户名和密码
String userCode = req.getParameter("userCode");
String userPassword = req.getParameter("userPassword");
// 和数据库中的密码进行对比,调用业务层
UserServiceImpl userService = new UserServiceImpl();
User user = userService.login(userCode, userPassword); // 这里已经把登录的人查出来了
if (user !=null) { // 查有此人,可以登录
// 将用户的信息放到Session中
req.getSession().setAttribute(Constants.USER_SESSION, user);
// 跳转到主页
resp.sendRedirect("jsp/frame.jsp");
} else { // 查无此人,无法登录
// 转发回登录页面,顺带提示它,用户名或密码错误
req.setAttribute("error", "用户名或密码不正确");
req.getRequestDispatcher("login.jsp").forward(req, resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 注册Servlet
<!--注册Servlet-->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>pers.dongyang.servlet.user.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
- Tomcat启动测试访问,确保以上功能成功
15.3 登录功能优化
注销功能:
思路:移除Session,返回登录页面
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 移除用户的Session
req.getSession().removeAttribute(Constants.USER_SESSION);
// 回到登录页面
resp.sendRedirect(req.getContextPath() + "/login.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注册xml
<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>pers.dongyang.servlet.user.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/jsp/logout.do</url-pattern>
</servlet-mapping>
登录拦截优化(退出后,不输入用户名密码,直接输入首页网址,不允许进入)
编写一个过滤器
public class SysFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req; // 为了获取Session
HttpServletResponse response = (HttpServletResponse) resp; // 为了重定向
// 过滤器,从Session获取用户
User user = (User) request.getSession().getAttribute(Constants.USER_SESSION);
if (user == null) { // 说明该用户已被移除或注销或未登录
response.sendRedirect("/smbms/error.jsp");
}else {
chain.doFilter(req, resp);
}
}
public void destroy() {
}
}
注册
<!--用户登录拦截过滤器-->
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>pers.dongyang.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/jsp/*</url-pattern>
</filter-mapping>
15.4 密码修改
- 导入前端素材
<li><a href="${pageContext.request.contextPath }/jsp/pwdmodify.jsp">密码修改</a></li>
- 写项目,建议从底层向上写
- UserDao接口
// 修改当前用户密码(增删改返回值都是int)
public int updatePwd(Connection connection, int id, int password) throws Exception;
- UserDao接口实现类
// 修改当前用户密码(增删改返回值都是int)
public int updatePwd(Connection connection, int id, int password) throws Exception {
PreparedStatement pstm = null; // 3.创建PreparedStatement
// 8.考虑到返回值在if内定义无法return,所以将其定义提到if外
int updateRows = 0;
// 7.出于安全性考虑,进行判断
if (connection!=null) {
// 1.先写SQL语句
String sql = "update smbms_user set userPassword = ? where id = ?"; // 2.要执行sql语句需要创建PreparedStatement进行预编译
// 5.创建BaseDao参数params,跟问号按顺序对应
Object[] params = {password, id};
// 4.调用BaseDao去执行(参数没有的去创建,比如params)
updateRows = BaseDao.execute(connection, pstm, sql, params);
// 6.释放资源
BaseDao.closeResource(connection, pstm, null);
}
// 9.返回被修改的行数
return updateRows;
}
- UserService层
// 根据用户id修改密码(在数据库持久化操作中增删改返回值都是int,表示的是修改的数据的行数,在业务层这里使用boolean表示是否修改成功)
public boolean updatePwd(int id, int password);
- UserService实现类
public boolean updatePwd(int id, int password) {
// 1.业务层可能存在事务,失败要回滚,把Connection提前
Connection connection = null;
// 4.设置flag判断是否修改成功,默认失败
boolean flag = false;
// 2.获取数据库连接
connection = BaseDao.getConnection();
// 3.修改密码
// 如果被修改的行数大于0,说明SQL语句执行成功, 将异常try catch
try {
if (userDao.updatePwd(connection, id, password) > 0) {
// 5.说明修改成功
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6.关闭资源
BaseDao.closeResource(connection, null, null);
}
return flag;
}
- Servlet记得实现复用需要提取出方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getParameter("method");
if (method.equals("savepwd") && method != null) {
this.updatePwd(req, resp);
}
}
public void updatePwd(HttpServletRequest req, HttpServletResponse resp) {
// 1.从Session中获取用户id
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
// 2.获取前端参数 取newpassword更新替换原来密码
String newpassword = req.getParameter("newpassword");
// 6.设置flag判断是否修改成功,默认失败
boolean flag = false;
// 3.判断
if (o != null && !StringUtils.isNullOrEmpty(newpassword)) { // 如果对象不为空,并且密码不存在或密码不为空
// if (o != null && newpassword != null && newpassword.length() != 0) 这个if判断等效于上一句,但是上一句逼格高
// 4.调用Service层
UserService userService = new UserServiceImpl();
// 5.修改密码,返回修改成功与否的boolean值
flag = userService.updatePwd(((User) o).getId(), newpassword);
if (flag) {
// 6.如果修改成功,返回一句话
req.setAttribute("message", "修改密码成功,请使用新密码重新登录");
// 7.密码修改成功,移除当前Session
req.getSession().removeAttribute(Constants.USER_SESSION);
} else {
// 8.如果修改成功,返回一句话
req.setAttribute("message", "密码修改失败");
}
} else {
// 9.如果新密码有问题,返回一句话
req.setAttribute("message", "新密码格式不正确");
}
// 10.修改完转发
try {
req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
<!--UserServlet修改密码-->
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>pers.dongyang.servlet.user.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/jsp/user.do</url-pattern>
</servlet-mapping>
- 测试
Ajax优化密码修改
- 阿里的fastjson
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
- 后台代码修改
// 修改密码
public void updatePwd(HttpServletRequest req, HttpServletResponse resp) {
// 1.从Session中获取用户id
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
// 2.获取前端参数 取newpassword更新替换原来密码
String newpassword = req.getParameter("newpassword");
// 6.设置flag判断是否修改成功,默认失败
boolean flag = false;
// 3.判断
if (o != null && !StringUtils.isNullOrEmpty(newpassword)) { // 如果对象不为空,并且密码不存在或密码不为空
// if (o != null && newpassword != null && newpassword.length() != 0) 这个if判断等效于上一句,但是上一句逼格高
// 4.调用Service层
UserService userService = new UserServiceImpl();
// 5.修改密码,返回修改成功与否的boolean值
flag = userService.updatePwd(((User) o).getId(), newpassword);
if (flag) {
// 6.如果修改成功,返回一句话
req.setAttribute("message", "修改密码成功,请使用新密码重新登录");
// 7.密码修改成功,移除当前Session
req.getSession().removeAttribute(Constants.USER_SESSION);
} else {
// 8.如果修改成功,返回一句话
req.setAttribute("message", "密码修改失败");
}
} else {
// 9.如果新密码有问题,返回一句话
req.setAttribute("message", "新密码格式不正确");
}
// 10.修改完转发
try {
req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 验证旧密码,Session中有用户的密码
public void pwdmodify(HttpServletRequest req, HttpServletResponse resp) {
// 1.从Session中获取用户id
Object o = req.getSession().getAttribute(Constants.USER_SESSION);
// 2.获取前端参数 取oldpassword更新替换原来密码
String oldpassword = req.getParameter("oldpassword");
// 5.使用万能的Map封装 true false sessionerror error结果集
HashMap<String, String> resultMap = new HashMap<String, String>();
if (o==null) { // 3.如果Session失效或过期
// 4.告诉前端出现问题
resultMap.put("result", "sessionerror");
}else if (StringUtils.isNullOrEmpty(oldpassword)) { // 6.输入的密码为空
resultMap.put("result", "error");
}else {
String userPassword = ((User) o).getUserPassword(); // Session中用户的密码
if (oldpassword.equals(userPassword)) { // 如果oldpassword和Session中的密码一样
resultMap.put("result", "true");
}else { // 密码错误
resultMap.put("result", "false");
}
}
try {
// 使用json格式接收
resp.setContentType("application/json");
// 创建流
PrintWriter writer = resp.getWriter();
// JSONArray 阿里的JSON工具类,转换格式时使用
/**
* resultMap = ["result", "true", "result", "false", "result", "sessionerror", "result", "error"]
* JSON格式:{key:value}
*/
writer.write(JSONArray.toJSONString(resultMap)); // 把结果集变成JSON字符串格式
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
15.5 用户管理实现
思路:一个Servlet查询三个东西,用户列表,角色列表和分页
-
导入分页的工具类
-
用户列表页面导入
实现步骤
1. 获取用户数量
(1) UserDao
// 查询用户总数
public int getUserCount(Connection connection, String userName, int userRole) throws Exception;
(2) UserDaoImpl
// 根据用户名或用户角色查询用户总数[最难理解的SQL语句]
public int getUserCount(Connection connection, String userName, int userRole) throws Exception {
PreparedStatement pstm = null;
ResultSet rs = null;
int count = 0;
if (connection != null) {
StringBuffer sql = new StringBuffer(); // 考虑到这里的查询比较复杂需要使用sql拼接,所以使用StringBuffer存储sql
sql.append("select count(1) as count from smbms_user u,smbms_role r where u.userRole = r.id");
ArrayList<Object> list = new ArrayList<Object>();// 存放我们的参数(即?)
if (!StringUtils.isNullOrEmpty(userName)) { // 如果用户名不为空,继续append
sql.append(" and u.userName like ?"); // ? 表示模糊查询字符串,格式 %....
list.add("%" + userName + "%"); // list.index=0
}
if (userRole > 0) { // 判断角色序号是否大于0(角色序号为1 2 3,大于0表示选定了角色)
sql.append(" and u.userRole = ?");
list.add(userRole); // list.index=1
}
// 把list转换成数组
Object[] params = list.toArray();
// 输出完整的SQL语句
System.out.println("UserDaoImpl-> getUserCount:" + sql.toString());
// 执行sql语句
rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
// 从结果集中获取最终的数量
if (rs.next()) {
count = rs.getInt("count");
}
// 释放资源
BaseDao.closeResource(null, pstm, rs);
}
return count;
}
(3) UserService
// 查询记录数
public int getUserCount(String userName, int UserRole);
(4) UserServiceImpl
// 查询记录数
public int getUserCount(String userName, int UserRole) {
Connection connection = null;
int count = 0;
try {
connection = BaseDao.getConnection();
count = userDao.getUserCount(connection, userName, UserRole);
} catch (Exception e) {
e.printStackTrace();
} finally {
BaseDao.closeResource(connection, null, null);
}
return count;
}
2. 获取用户列表
(1) userDao
// 获取用户列表,通过条件查询-userList(实现分页)
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception;
(2) userDaoImpl
public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception {
PreparedStatement pstm = null;
ResultSet rs = null;
List<User> userList = new ArrayList<User>();
if (connection != null) {
StringBuffer sql = new StringBuffer();
sql.append("select u.*, r.roleName as userRoleName \n" +
"from smbms_user u, smbms_role r \n" +
"where u.userRole = r.id");
List<Object> list = new ArrayList<Object>();
if (!StringUtils.isNullOrEmpty(userName)) {
sql.append(" and u.userName like ?");
list.add("%" + userName + "%");
}
if (userRole>0) {
sql.append(" and u.userRole = ?");
list.add(userRole);
}
/*
* 在数据库中,分页使用limit
* 参数:startIndex, pageSize
* startIndex当前页起始元素索引 = (当前页码 - 1) * 页面大小
* 假设每页5个元素
* 参数:0, 5 页码:1 数据库起始元素索引:0 总元素:0 1 2 3 4
* 参数:5, 5 页码:2 数据库起始元素索引:5 总元素:5 6 7 8 9
* 参数:10, 5 页码:3 数据库起始元素索引:10 总元素:10 11 12 13 14
* ...
* */
sql.append(" order by creationDate DESC limit ?,?");
currentPageNo = (currentPageNo - 1) * pageSize;
list.add(currentPageNo);
list.add(pageSize);
Object[] params = list.toArray();
System.out.println("sql ----> " + sql.toString());
rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
while (rs.next()) {
User _user = new User();
_user.setId(rs.getInt("id"));
_user.setUserCode(rs.getString("userCode"));
_user.setUserName(rs.getString("userName"));
_user.setGender(rs.getInt("gender"));
_user.setBirthday(rs.getDate("birthday"));
_user.setPhone(rs.getString("phone"));
_user.setUserRole(rs.getInt("userRole"));
_user.setUserRoleName(rs.getString("userRoleName"));
userList.add(_user);
}
BaseDao.closeResource(null, pstm, rs);
}
return userList;
}
(3) userService
// 根据条件查询用户列表
public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize);
(4) userServiceImpl
public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize) {
Connection connection = null;
List<User> userList = null;
System.out.println("queryUserName ----> " + queryUserName);
System.out.println("queryUserRole ----> " + queryUserRole);
System.out.println("currentPageNo ----> " + currentPageNo);
System.out.println("pageSize ----> " + pageSize);
try {
connection = BaseDao.getConnection();
userList = userDao.getUserList(connection, queryUserName, queryUserRole, currentPageNo, pageSize);
} catch (Exception e) {
e.printStackTrace();
} finally {
BaseDao.closeResource(connection, null, null);
}
return userList;
}
3. 获取角色操作
为了统一,可以把角色的操作单独建包,和pojo包中实体类对应
(1) RoleDao
package pers.dongyang.dao.role;
import pers.dongyang.pojo.Role;
import java.sql.Connection;
import java.util.List;
public interface RoleDao {
// 获取角色列表
public List<Role> getRoleList(Connection connection) throws Exception;
}
(2) RoleDaoImpl
package pers.dongyang.dao.role;
import pers.dongyang.dao.BaseDao;
import pers.dongyang.pojo.Role;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class RoleDaoImpl implements RoleDao{
// 获取角色列表
public List<Role> getRoleList(Connection connection) throws Exception {
PreparedStatement pstm = null;
ResultSet rs = null;
ArrayList<Role> roleList = new ArrayList<Role>();
if (connection!=null) {
String sql = "select * from smbms_role";
Object[] params = {};
rs = BaseDao.execute(connection, pstm, rs, sql, params);
while (rs.next()) {
Role _role = new Role();
_role.setId(rs.getInt("id"));
_role.setRoleCode(rs.getString("roleCode"));
_role.setRoleName(rs.getString("roleName"));
roleList.add(_role);
}
BaseDao.closeResource(null, pstm, rs);
}
return roleList;
}
}
(3) RoleService
package pers.dongyang.service.role;
import pers.dongyang.pojo.Role;
import java.util.List;
public interface RoleService {
// 获取角色列表
public List<Role> getRoleList();
}
(4) RoleServiceImpl
package pers.dongyang.service.role;
import pers.dongyang.dao.BaseDao;
import pers.dongyang.dao.role.RoleDao;
import pers.dongyang.dao.role.RoleDaoImpl;
import pers.dongyang.pojo.Role;
import java.sql.Connection;
import java.util.List;
public class RoleServiceImpl implements RoleService{
// 引入Dao
private RoleDao roleDao;
// 实例化
public RoleServiceImpl() {
roleDao = new RoleDaoImpl();
}
public List<Role> getRoleList(){
Connection connection = null;
List<Role> roleList = null;
try {
connection = BaseDao.getConnection();
roleList = roleDao.getRoleList(connection);
} catch (Exception e) {
e.printStackTrace();
} finally {
BaseDao.closeResource(connection, null, null);
}
return roleList;
}
}
4. 用户显示的Servlet
(1) 获取用户前端的数据(查询)
(2) 判断请求是否需要执行,看参数的值判断
(3) 为了实现分页,需要计算出当前页面和总页面,页面大小
(4) 用户列表展示
(5) 返回前端
// 重点难点
public void query(HttpServletRequest req, HttpServletResponse resp) {
// 查询用户列表
// 从前端获取的临时变量
String queryUserName = req.getParameter("queryUserName");
String queryUserRoleTemp = req.getParameter("queryUserRole");
String pageIndex = req.getParameter("pageIndex");
int queryUserRole = 0; // 存放前端字符串queryUserRoleTemp解析出来的数字123对应不同的role
// 获取用户列表
UserServiceImpl userService = new UserServiceImpl();
List<User> userList = null;
// 第一次走这个请求一定是首页,并且页面大小固定
int pageSize = 5; // 建议把pageSize写到配置文件中方便后期修改
int currentPageNo = 1; // 当前页码默认是第一页
if (queryUserName == null) { // 如果名字为空,则手动赋值为""
queryUserName = "";
}
if (queryUserRoleTemp != null && !queryUserRoleTemp.equals("")) { // 如果下拉框角色名不为空,则进行字符串解析
queryUserRole = Integer.parseInt(queryUserRoleTemp);
}
if (pageIndex != null) {
currentPageNo = Integer.parseInt(pageIndex); // 解析当前页面页码
}
// 获取用户总数 (分页:存在上一页,下一页的情况,使用pageSupport工具类)
int totalUserCount = userService.getUserCount(queryUserName, queryUserRole);
// 使用pageSupport工具类设置值
PageSupport pageSupport = new PageSupport();
pageSupport.setCurrentPageNo(currentPageNo); // 设置当前页码,值来自前端字符串解析
pageSupport.setPageSize(pageSize); // 设置页面大小,值来自自定义,后续建议从配置文件读入
pageSupport.setTotalUserCount(totalUserCount); // 设置用户总数,值来自调用业务层方法返回
int totalPageCount = pageSupport.getTotalPageCount(); // 通过工具类获取页面总数
// 控制首页和尾页
if (currentPageNo<1) { // 控制页码小于1时停留在第一页
currentPageNo = 1;
} else if (currentPageNo>totalPageCount) { // 控制页码大于最后一页时停留在最后一页
currentPageNo = totalPageCount;
}
// 获取用户列表展示
userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, pageSize); // 上面的操作都是为了获取这个方法的参数
req.setAttribute("userList", userList); // 将用户列表信息传给前端,匹配前端item后面的变量名
// 获取角色列表展示
RoleServiceImpl roleService = new RoleServiceImpl();
List<Role> roleList = roleService.getRoleList();
req.setAttribute("roleList", roleList); // 将用户列表信息传给前端,匹配前端item后面的变量名
// 传递其他信息给前端
req.setAttribute("totalUserCount", totalUserCount);
req.setAttribute("totalPageCount", totalPageCount);
req.setAttribute("currentPageNo", currentPageNo);
req.setAttribute("queryUserName", queryUserName);
req.setAttribute("queryUserRole", queryUserRole);
// 返回前端
try {
req.getRequestDispatcher("userlist.jsp").forward(req, resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
自言自语小黄鸭调试法!
可以使用IDEA对.class文件反编译直接打开,操作步骤:直接将target目录中生成的class文件放到IDEA中打开即可。