1. 基本概念
1.1 前言
web:开发:
- web,网页的意思,www.baidu.com
- 静态web:
- html.css
- 提供给所有人看的数据始终不会发生变化
- 动态web
-
每个人在不同时间不同地点看到的信息各不相同
-
例如:淘宝,大部分网站...
-
技术栈:Serverlt,ASP,php
-
- 在java中,动态web资源开发的技术统称为javaWeb
1.2web应用程序
web应用程序:可以提供浏览器访问的程序
- a.html b.html---多个web资源可以被外界访问,对外界提供服务
- 你们能访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上
- URL
- 这些统一的Web资源会被统一放到一个文件夹下,这就是一个web应用程序->Tormcat服务器
- 一个web应用由多部份组成
(静态web,动态web)- html,css,js
- jsp,servert
- java程序
-jar包 - 配置文件(Properties)
web应用程序编写完毕后,若想提供给外界访问:需要一个服务器来统一管理
1.3静态web
- *.html:都是网页的后缀,如果服务器上存在这些东西,我们就可以直接读取,通络
- 静态web存在缺点
- Web页面无法动态更新,所有用户看到的都是同一个页面
- 轮廓图 点击特效 伪动态
- javaScript[实际开发中,他用的最多]
- VBScript
- 他无法和数据库交互(数据无法持久化,用户无法交互)
- Web页面无法动态更新,所有用户看到的都是同一个页面
1.4动态web
页面会动态显示,:"web的页面展示的效果因人而异
缺点
- 加入服务器的动态web资源出现了错误,我们需要重新编写我们的后台程序重新发布(停机维护)
优点
- Web页面可以动态更新,所有用户看到的都是不是同一个页面
- 他可以和数据库交互(数据持久化:注册,商品信息)
2.Web服务器
2.1技术讲解
ASP:
- 国内最早流行的,
- 在HTML中嵌入了VB脚本,ASP+COM
- 在ASP开发中,基本一个页面都有几千行的业务代码,页面及其混乱,所以维护成本高
- C#
- IIS
<h1>
<h1><h1>
<h1>
<h1>
<h1>
</h1>
<!--在这里面写一些java代码-->
<%
System.ouot.println("hello")
%>
</h1>
</h1>
</h1></h1>
</h1>
php:
- PHP开发速度快,功能强大且跨平台,代码简单(70%,WP)
-无法承载大访问量的情况(局限性)
JSP/Servlet:
B/S:浏览器和服务器
C/S:客户端和服务器
- sun公司主推的B/S架构
- 基于java语言的(所有的大公司或者一些开源的组件都是java写的)
- 可以承载三高问题带来的影响
- 语法像ASP,ASP--JSP,加强市场强度
Web服务器
服务器是一种被动的操作,用来处用户的请求和给用户的一些响应信息
IIS:
- 微软的 :ASP Windows中自带的
Tomcat:
-
Tomcat 是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为比较流行的Web 应用服务器。
-
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个java初学web来说,他是最佳选择
-
Tomcat 实际上运行JSP 页面和Servlet。Tomcat最新版本为10.0.14。
下载Tomcat
- 1.安装 or 解压
- 了解配置文件和目录结构
- 这个东西的作用
3.Tomcat
3.1 安装Tomcat官网
3.2 Tomcat启动和配置
-
Tomat文件目录组成
-
启动,关闭Tomcat
测试访问:http://localhost:8080/ -
可能的问题
- java环境变量没有配置
- 乱码问题:配置文件中的设置
- 闪退问题:需要配置兼容性
3.3配置
通过该文件可以配置启动端口:
- tomcat的默认端口号:8080
- mysql:3306
- http:80
- https:443
<!--将端口号改为8081,在上面访问网站时则进入:http://localhost:8081/-->
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
可以配置主机名:
- 默认的主机名为 localhost->127.0.0.1
- 默认的网站应用存放位置为:webapps
<!--可更改name主机名 -->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
在网站的该文件中就可设置网站显示:
高难度面试题
请你谈谈网站时如何访问的:
-
输入一个域名:回车
-
检查本机的 C:\Windows\System32\drivers\etc\hosts_lg_bak 的配置文件中有没有这个域名映射:
- 有:直接返回对应ip地址
127.0.0.1 www.lupeng.com
- 没有,去DNS服务器上找,找到就返回,找不到就返回找不到
-
可以配置一下环境变量
3.4发布一个Web网站
不会就先模仿
- 将自己写的网站,放到服务器(Tomcat)中指定的web应用文件夹(webapps)下,就可以访问了
网站应该有的结构
--webapps:Tomcat服务器web目录
- ROOT
- study:网站目录名
- WEB-INF
- classes:Java程序
- lib:wb应用程序所依赖的jar包
- web.xml:网站配置文件
- index.html :默认的首页
- static(静态网站)
- css
- sty.css
- js
- img
4.HTTP
4.1什么时HTTP
HTTP(超文本传输协议提)是一个简单的请求-响应协议,它通常运行在TCP之上。
- 文本:html,字符串,...
- 超文本:图片,音乐,视频,定位,地图...
- 默认端口号:80
Https: s--安全的
- 默认端口号:443
4.2 两个时代
- http1.0
- HTTP/1.0:客户端可以与web服务器连接,只能获得一个web资源,请求获得资源后后断连接
- http2.0
- HTTP/1.1:客户端可以与服务器连接后,可以获得多个web资源
4.3Http请求
- 客户端-->发请求-->服务器
百度:
Resquest URL: https://www.baidu.com/ 请求地址
Resquest Method: GET get方法/post方法
Status Code: 200 OK 状态码:200
Remote Address: 14.215.177.39:443 远程
Referrer Policy: origin-when-cross-origin 协议
Accept: text/htm
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 //语言
Cache-Control: max-age=0
Connection: keep-alive
1.请求行
- 请求行中的请求方式:GET
- 请求方式:Get,Post,HEAD,DELETE,PUT,TRACT
- get: 请求能狗携带的参数比较少,大小由限制,会在浏览器的url地址连显示内容,不安全但是高效
- post:请求能够携带的参数没有限制,大小没有限制,不会在浏览器中的url地址栏显示数据内容,安全但不高效
2.请求头
Accept: 告诉浏览器,它所支持的数据类型
Accept-Encoding: 支持那种编码格式, GBK UTF-8 GB2312 ISo8859-1
Accept-Language: 告诉浏览器,它的语言环境 //语言
Cache-Control: 缓冲控制
Connection: 告诉浏览器,请求时完成是断开还是保持连接
HOST:主机.../.
4.4Http响应
- 服务器-->响应-->客户端
百度(部分要学的):
Bdpagetype: 2
Bdqid: 0xbc5c4dfd000d37b0
Cache-Control: private //缓存控制
Connection: keep-alive //连接
Content-Encoding: gzip //编码
Content-Type: text/html;charset=utf-8 //类型
1.响应体
Accept: 告诉浏览器,它所支持的数据类型
Accept-Encoding: 支持那种编码格式, GBK UTF-8 GB2312 ISo8859-1
Accept-Language: 告诉浏览器,它的语言环境 //语言
Cache-Control: 缓冲控制
Connection: 告诉浏览器,请求时完成是断开还是保持连接
HOST:主机.../.
Refrush:告诉客户端,多久刷新一次
Location:让网页重新定位
响应状态码(重点)
200:请求响应成功 200
3***:请求重定向
- 重定向:你重新到我给你的新位置
4**:找不到资源 404
- 资源不存在
5***:服务器代码错误 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
在测试Maven是否成功,保证必须被指完毕
5.4阿里云镜像
- 镜像:mirrors
- 作用:加速我们的下载
5.5 本地仓库
在本地的仓库,远程仓库
建立一个本地仓库,localRepository
-
如果没有配置,则默认在该位置建立本地仓库
| Default: ${user.home}/.m2/repository -
配置本地仓库
E:\javaWeb\apache-maven-3.8.6\maven-repo
5.6在idea中使用Maven
- 启动idea
- 创建一个Maven项目
-
等待项目初始化完毕
-
观察Maven仓库中多了什么多西
-
idea中的Maen设置
注意:idea项目创建成功后看一眼Maven的配置
- 到这里Maven在idea中的配置和使用就ok了
5.7 创建一个普通的Maven项目
-
第一步:
-
第二步:
这个只有在web应用下才会有
5.8标记文件夹功能
-
法一
-
法二
5.9 在idea中配置Tomcat
解决警告问题。
为什么?
我们访问一个网站需要指定一个文件夹名字
Maven侧边栏使用:
5.10 pom文件
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>com.peng</groupId>
<artifactId>javaWeb-01-Maven</artifactId>
<version>1.0-SNAPSHOT</version>
<!--项目的打包方式
jar:java应用
war:JavaWeb应用
-->
<packaging>war</packaging>
<!--可删-->
<!--<name>javaWeb-01-Maven 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.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<!--项目依赖-->
<dependencies>
<dependency>
<!--项目依赖的具体jar包-->
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--项目构建用的东西-->
<build>
<finalName>javaWeb-01-Maven</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>
Maven的denpendcy可以自动导入所依赖的jar包
- maven由于它的约定大于配置我们之后可能遇到我们所写的配置文件无法正常导出
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
- Maven的jar关联图
6.Maven仓库的使用
-
在Tomcat中的例子中找到一个Servlet案例
-
用该例子在java包下创建
-
- 也有没有在仓库中找到所需包这时因为这是在Tomcat中找的例子,所以可能会在Tomcat中找到
7.Servlet
7.1Servlet简介
- Servlet就是sun公司开发动态web的一门技术
- Sun在这这API中提供了一个接口叫做,Servlet,如果想开发一个Servlet程序,只需要完成两个小步骤
- 编写一个类,实现Servlet接口
- 把开发好的java类部署到web服务器中
我们把实现类Servlet接口的java程序叫做,Servlet
7.2 HelloServlet
Servlet接口在sun公司有两个默认的实现类:HttpServlet,GenericServlet
-
构建一个普通的Maven项目,删掉里面的src目录,以后就在这个项目里面建立Module;这个空的工程就是Maven的主工程
-
关于Maven父子工程的理解
在父项目中会有
<modules>
<module>servlet-01</module>
</modules>
子项目会有
<parent>
<artifactId>javaweb-01.servlet</artifactId>
<groupId>com.peng</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的java子项目可以直接使用
sun extends father
-
Maven环境优化
- 修改web.xml为最新的
- 将Maven的结构搭建完整(java,resoure)
- 修改web.xml为最新的
-
编写一个Servlet程序
- 编写一个普通类
- 实现Servlet接口,这里我们直接继承HttpServlet
public class HelloServlet extends HttpServlet {
//由于get或者post只是亲求实现的不同方式,可以相互调用,业务逻辑都一样。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// ServletInputStream inputStream = req.getInputStream();
// BufferedReader reader = req.getReader();//请求流
// ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter();//响应流
writer.println("Hello,Servlet.");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
-
编写Servlet的映射
为什么需要映射:我们写的是JAVA程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要再web服务中注册我们写的Servlet,还需要给他浏览器访问的路径
<!--注册Servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.peng.HelloServlet</servlet-class> </servlet> <!--servlet的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
配置Tomcat
注意配置项目发布的路径
- 启动测试
- 发现问题:
无法使用映射访问HelloSerlet中的动态页面
报错:报:类com.peng.HelloServlet不是Servlet
解决:https://blog.csdn.net/qq_40147863/article/details/87717566
大致是:Tomcat10之后包名不再是"javax.servlet”,则是改为"jakarta.servlet"
第一种解决办法:Tomcat版本改为10以下的版本
第二种解决办法:“javax.servlet”改为"jakarta.servlet”
- 发现问题:
7.3 servlet原理
Servlet是由Web服务器调用,web服务器再收到浏览器之后,会收到
7.4 Mapping问题
-
一个Servlet可以指定一个映射路劲
<!--servlet的请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <!--请求路劲--> <!-- <url-pattern>/hello/hello</url-pattern> 访问方法:localhost:8080/hello/hello --> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
一个Servlet可以指定多个映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello1</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-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello5</url-pattern> </servlet-mapping>
-
一个Servlet可以指定通用映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping> <!--默认请求路径--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
-
指定一些后缀或者前缀等等...
<!--可以自定义后缀实现请求映射 注意点:*前面不能加项目映射的路径 lu.peng /hello/li.peng都可以实现,只要以其结尾就行--> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.peng</url-pattern> </servlet-mapping>
- 扩充:处理404页面响应
- 每创建一个新的页面就需要进行serclet的配置
-
以上述404页面处理问题而引出一个问题:我们在访问页面(localhost:8080/s1/hello),这个网站时,此时我们的servlet配置里面的servlet-mapping中有两个
url-pattern 路径(/hello和/*)而访问上面网站时该优先走哪一个路径呢?- 优先级
指定了固定的映射优先级,他的优先级最高,如果找不到就会走默认的处理请求(/*)
7.5 Servlet对象
- 注意项:
web容器在启动的时候,他会为每个web程序创建一个对应的ServletContext对象,它代表的web应用;
-
共享数据:
我在这个Servlet中保存的数据,可以在另外一个Servlet中拿到
- 一个将数据放置在ServletContext中的类
package com.peng.servlet; import jakarta.servlet.*; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; 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,值:username System.out.println("hell0"); } }
- 一个从ServletContext中读取数据的类
package com.peng.servlet; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; public class GetServlet extends HelloServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String s =(String) servletContext.getAttribute("username"); /* 需设置页面格式,才能时响应回来的文件解码后能识别显示 否则就是乱码 */ resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); resp.getWriter().println("名字"+s); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
- 外加一个Servlet配置
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.peng.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.peng</url-pattern> </servlet-mapping> <servlet> <servlet-name>get</servlet-name> <servlet-class>com.peng.servlet.GetServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>get</servlet-name> <url-pattern>/getUser</url-pattern> </servlet-mapping>
- 获取初始化参数
-
注册Servlet
<servlet> <servlet-name>gp</servlet-name> <servlet-class>com.peng.servlet.ServletDomo03</servlet-class> </servlet> <servlet-mapping> <servlet-name>gp</servlet-name> <url-pattern>/dburl</url-pattern> </servlet-mapping>
-
获取配置
ServletContext context=this.getServletContext(); /* getInitParameter:获取一些配置参数 */ String url=context.getInitParameter("url"); resp.getWriter().write(url);
- 在web.xml中的部分初始化参数
<context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306</param-value> </context-param>
-
请求转发
System.out.println("进入了ServletDemo04");
ServletContext context=this.getServletContext();
RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp"); //转发的请求路径
requestDispatcher.forward(req,resp);//调用forward实现请求转发
<servlet>
<servlet-name>sd4</servlet-name>
<servlet-class>com.peng.servlet.ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sd4</servlet-name>
<url-pattern>/forward</url-pattern>
</servlet-mapping>
转发:
ServletDemo04该类中通过requestDispatcher = context.getRequestDispatcher("/gp"); 方法,
转发到了localhost:8080/s1/gp该页面,实际实在给页面显示了另一个页面的内容,本身页面并没有跳转,所以网页地址是不变的
- 读取资源文件
Properties
- 在java目录下新建properties
- 在resoures目录下新建properties
发现:都被打包到了同一路径下:classes,我们俗称为类路径
思路:需要一个文件流
```java
/*
getResourceAsStream:把资源变成文件流
*/
InputStream is=servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");
InputStream is2=servletContext.getResourceAsStream("/WEB-INF/classes/com/peng/servlet/aa.propeties");
Properties properties = new Properties();
properties.load(is2);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
resp.getWriter().write(username+":"+password);
```
7.6 HttpServletResponse
web服务器接收到客户端的http请求,会针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletRespons;
-
如果要获取客户端请求过来的参数;找HttpServletRequest
-
如果要给客户端响应一些信息:找HttpServletResponse
1. 简单分类
负责向浏览器发送数据的方法:
-
ServletOutputStream getOutputStream() throws IOException;
-
PrintWriter getWriter() throws IOException;
负责向浏览器发送一些响应头的方法:
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setBufferSize(int var1);
void setCharacterEncoding(String var1) throws UnsupportedEncodingException;
响应的状态常量:
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
2. 常见应用
- 向浏览器输出消息(前例)
- 下载文件
让浏览器支持(Content-disposition)下载我们需要的东西
1. 要获取下载文件的路径
2. 下载的文件名是什么
3. 想办法让浏览器支持下载我们需要的东西
4. 获取下载文件的输入流
5. 创建缓冲区
6. 获取OutputStream对象
7. 将FileOutpoutSteam写到buffer缓冲区
8. 使用OutputStream将缓冲区中的数据输出到客户端
```java
1. 要获取下载文件的路径
ServletContext servletContext = this.getServletContext();
String realPath = "E:\\javaweb-01.servlet\\response\\target\\classes\\妖刀姬.png";
//E:\javaWeb\apache-tomcat-10.0.23\webapps\r\妖刀姬.png
// E:\javaweb-01.servlet\response\target\classes\妖刀姬.png 应该使用target中的路径
System.out.println("下载文件的路径:"+realPath);
//2. 下载的文件名是什么
String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
//3. 想办法让浏览器支持(Content-disposition)下载我们需要的东西
resp.setHeader("Content-disposition","attachment;fileName="+URLEncoder.encode(fileName,"utf-8"));
/*
如果文件名是中文,这里的文件名会出现乱码,需要对文件名进行进行编码转换
用URLEncoder.encode()编码
*/
//4. 获取下载文件的输入流
FileInputStream in=new FileInputStream(realPath);
//5. 创建缓冲区
int len=0;
byte[] buffer = new byte[1024];
//6. 获取OutputStream对象
ServletOutputStream os= resp.getOutputStream();
//7. 将FileOutputSteam写到buffer缓冲区, 使用OutputStream将缓冲区中的数据输出到客户端
while((len=in.read(buffer))>0){
os.write(buffer,0,len);
}
//8.关闭资源
in.close();
os.close();
```
-
验证码功能
验证码如何来?
- 前端实现
- 后端实现,需要用到java的图片类,生成一个图片
//如何让浏览器5秒自动刷新一次; resp.setHeader("refresh","3"); //在内存中创建图片 BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_3BYTE_BGR); //得到图片 Graphics2D graphics =(Graphics2D) image.getGraphics();//一支笔 //设置图片背景颜色 graphics.setColor(Color.white); graphics.fillRect(0,0,80,20); //给图片写数据 graphics.setColor(Color.BLUE); graphics.setFont(new Font(null,Font.BOLD,20)); graphics.drawString(makeNum(),0,20); /* 告诉浏览器这个请求用图片的方式打开 */ resp.setContentType("image/png"); /* 网站存在缓存,不让他存在缓存 */ resp.setDateHeader("expires",-1); resp.setHeader("Cache-Control","no-cache"); resp.setHeader("Pragma","no-cache"); //把图片写给浏览器 ImageIO.write(image, "png", resp.getOutputStream()); //生成随机数 private String makeNum(){ Random random = new Random(); String num=random.nextInt(99999999) + "";//这里随机数不一定生成的就是八位数 StringBuffer stringBuffer = new StringBuffer(); for (int i = 0; i < 7-num.length(); i++) {//这里循环创建数保证数一定是7位数 stringBuffer.append("0"); } num= stringBuffer.toString()+num; return num; }
-
实现重定向
一个web资源A收到客户端B请求后,他会通知客户端B去访问另一个web资源C,这个过程叫做重定向
常见场景
- 用户登录页面跳转
用 sendRedirect() 实现
resp.sendRedirect("/image");
用该重定向后,原页面会跳转到所设置页面
resp.sendRedirect("/r/image");
要想使页面生效就必须加上项目路径
-
重定向信息
-
重定向原理
resp.setHeader("Location","/r/image");
resp.setStatus(302);
- 面试题:重定向与转发的区别
- 相同点: 页面都会实现跳转
- 不同点:
- 请求转发的时候,url不会产生变化
- 重定向时候,url地址栏会发生变化
与前面例子说所的请求转发有着本质的不同
7.7 HttpServletRequest
HttpSercletRequest代表客户端的请求,用户通过http协议访问服务器,HTTP请求中的所有信息会被封锁到HttpServletRequest,通过HttpServletRequest的这个方法,获得客户端的所有信息。
- request小应用一:
1.获取前端传递参数,请求转发
只重点掌握 req.getParamter和 req,getParamterValues
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码
req.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);
System.out.println(password);
System.out.println(Arrays.toString(hobbys));
System.out.println("================================");
//重定向
// resp.sendRedirect("/r/success");
//设置响应编码防止乱码
resp.setCharacterEncoding("utf-8");
//请求转发
//这里的 / 代表当前的web应用
// req.getRequestDispatcher("/r/success.jsp").forward(req,resp);就会报错
//报错为消息地址是/r/r/success.jsp,
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
8.Cookie Session
8.1 会话
- 会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话
一个网站怎么证明你来过??
客户端 服务端
1.服务端给客户端一个Cookie(信件),客户端下次访问服务端带上信件就可以了(Cookie)
2.服务器登记你来过了,下次你来的时候我来匹配你。(Seesion)
- 有状态会话:一个同学来过教师,下次再来教师,我们会知道这个同学,曾经来过。称之为有状态会话
8.2保存会话的两种技术
cookie
- 客户端技术 (响应,请求)
session
- 服务器技术,利用这个技术可以保存用户的会话信息。我们可以把信息或者数据放在session中。
常见:网站登录后不用二次登录就直接进入网站了,(bilibili)
8.3 cookie
快速查看一个类的方法 ctrl+o
从请求中拿到cookie信息,然后服务器响应给客户端。
- 获得cookie
//cookie 服务器端从客户端获取
Cookie[] cookies = req.getCookies();//这里返回数组,cookie可能存在多个
- 获得cookie中的键值对
cookie.getName()
cookie.getValue()
- 新建一个cookie
Cookie cookie = new Cookie("lastLoginTime", String.valueOf(System.currentTimeMillis()));
- 设置cookie的有效期
cookie.setMaxAge(24*60*60);
- 相应给客户端cookie
resp.addCookie(cookie);
cookie:一般会保存在本地的用户目录下 appdata
一个网站cookie是否存在上限?
- 一个cookie只能保存一个信息
- 一个web站点可以给浏览器发送多个cookie
- 300个cookie是浏览器上限
- Cookie大小有限制 4kb
删除cookie
- 不设置有效期,关闭浏览器,自动失效
- 设置有效期时间为0
在cookie传输中文字符时,需要进行URLEncoder.encode编码 URLDecoder.decode解码
8.4 Session(重点)
什么是session?
- 服务器会给每一个用户(浏览器)创建一个Session对象
- 与个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在
- 用户登录之后,整个网站它都可以访问(该网站的同行证
Session和Coookie的区别
- Cookie是把用户的数据给用户的浏览器,浏览器保存
- Session把用户的数据写到用户独占的session中,服务器端保存 (保存重要信息,减少服务器资源的浪费)
- Session对象有服务器创建
使用场景
- 保存一个登录用户的信息
- 购物车信息
- 经常在整个网站中使用的数据 将其保存在Session中
使用Session
//SesionDemo01
//解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//得到Session
HttpSession session = req.getSession();
//给Session存东西
session.setAttribute("name", new Person("卢鹏",21));
/*
value值可以存object
*/
//获取Session的id
String id = session.getId();
//判断是Session是不是新创建的
if(session.isNew()){
resp.getWriter().write("Session创建成功,ID为:"+"");
}else{
resp.getWriter().write("Session已经在服务器中存在了");
}
//Session在创建的时候做了什么?
/*
好像创建了这样一个cookie
Cookie cookie=new Cookie("JSESSIONID","sessionId");
resp.addCookie(cookie)
*/
//SessionDemo02
//解决乱码问题
req.setCharacterEncoding("utf-8");
resp.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());
//SessionDemo03
HttpSession session = req.getSession();
//取消session的参数
session.removeAttribute("name");
//手动注销session
session.invalidate();
会话自动过期
<!--设置Session默认失效时间-->
<session-config>
<!--15分钟后Session失效,以分钟为单位-->
<session-timeout>15</session-timeout>
</session-config>
ServletContext与Session的区别
9. JSP
9.1 什么是JSP?
java server pages:服务器端页面,也和servlet一样用于开发动态web技术
最大特点:
- 写JSP就像在写HTML
- 区别:
- HTML只给用户提供给静态数据
- JSP页面中可以嵌入java代码,为用户提供动态数据
9.2 JSP原理
思路:JSP到底怎么执行?
-
代码层面每任何问题
-
服务器端内部工作
- tomcat中有一个work目录
- IDEA中使用Tomcat的话会在IDEA的tomcat中生成一个work目录
- tomcat中有一个work目录
我电脑的地址:
E:\java-idea\ideaIU_2021.2.3_Portable\ideaIU_2021.2.3_Portable\bin\IdeaConfig\system\tomcat\fed2f09e-c496-4018-b279-fdb23ad0c0c6\work\Catalina\localhost\peng\org\apache\jsp
发现页面转变为了java程序
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet
JSP最终也会被转换为java类
JSP本质上就是一个Servlet
package org.apache.jsp;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final jakarta.servlet.jsp.JspFactory _jspxFactory =
jakarta.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
...
- ndex_jsp extends org.apache.jasper.runtime.HttpJspBase继承了HttpJspBase类,
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
private static final long serialVersionUID = 1L;
protected HttpJspBase() {
}
public final void init(ServletConfig config) throws ServletException {
super.init(config);
this.jspInit();
this._jspInit();
...
HttpJspBase类本质上继承了 HttpServlet
所以 JSP本质上就是一个Servlet
在index_jsp.java中有一下三个方法
//初始化
public void _jspInit() {
}
//销毁
public void _jspDestroy() {
}
//JSPService
public void _jspService(final jakarta.servlet.http.HttpServletRequest request, final jakarta.servlet.http.HttpServletResponse response)
throws java.io.IOException, jakarta.servlet.ServletException
该方法做了一下几件事:
- 判断请求
if (!jakarta.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
final java.lang.String _jspx_method = request.getMethod();
if ("OPTIONS".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
return;
}
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
return;
}
}
2.内置了一些对象
final jakarta.servlet.jsp.PageContext pageContext; //页面上下文
jakarta.servlet.http.HttpSession session = null; //Session
final jakarta.servlet.ServletContext application; //applicationContext
final jakarta.servlet.ServletConfig config; //config
jakarta.servlet.jsp.JspWriter out = null; //out
final java.lang.Object page = this; //page
jakarta.servlet.jsp.JspWriter _jspx_out = null;
jakarta.servlet.jsp.PageContext _jspx_page_context = null;
final jakarta.servlet.http.HttpServletRequest request //请求
final jakarta.servlet.http.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("<html>\r\n")
这样的格式输出到前端
9.3 JSP基础语法
任何语言都有自己的语法,java中有,JSP作为java技术的应用,它拥有一些自己扩充的语法(了解),java所有语法都支持。
JSP表达式
<%--
JSP表达式
作用:一般用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
jsp脚本片段
<%--jsp脚本片段--%>
<%
int sum=0;
for (int i = 0; i < 100; i++) {
sum+=i;
}
response.getWriter().write("<h1> Sum="+sum+"</h1>");
%>
脚本片段的再实现
<%--在我们的代码中嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {
%>
<h1>hello,world <%=i%></h1>
<%
}
%>
以上jsp代码转换为java代码的体现在JspService方法中
out.write("\n");
out.write("\n");
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title>$Title$</title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write(" ");
out.write('\n');
out.write(' ');
out.write(' ');
out.print( new java.util.Date());
out.write("\n");
out.write("\n");
out.write("<hr>\n");
out.write(" ");
out.write('\n');
out.write(' ');
out.write(' ');
int sum=0;
for (int i = 0; i < 100; i++) {
sum+=i;
}
out.println("<h1> Sum="+sum+"</h1>");
out.write("\n");
out.write("\n");
out.write("\n");
out.write(" ");
int x=10;
out.println(x);
out.write("\n");
out.write("\n");
out.write(" <p>这是一个JSP文档</p>\n");
out.write(" ");
out.println(x);
out.write("\n");
out.write(" <hr>\n");
out.write("\n");
out.write(" ");
out.write("\n");
out.write("\n");
out.write(" ");
for (int i = 0; i < 5; i++) {
out.write("\n");
out.write(" <h1>hello,world ");
out.print(i);
out.write("</h1>\n");
out.write(" ");
}
out.write("\n");
out.write("\n");
out.write("\n");
out.write("\n");
out.write(" </body>\n");
out.write("</html>\n");
JSP声明
- 会被编译到JSP生成的类中,其他的则java到吗则会被生成到该类的JspService方法中
<%!
static{
System.out.println("loading servlet");
}
private int gloablVar=0;
private void peng(){
System.out.println("进入了peng方法");
}
%>
-
在JSP中嵌入java代码即可
-
EL表达式
- ${}和<%=>这种取值效果相同
<%--EL表达式--%>
<%
int i=10;
%>
${i}
JSP的语法有
<%%> 片段
<%=%> 表达式
<%!%> 设置全局
<%-- 注释 --%>
JSP注释,不会在客户端显示,HTML则会(!--注释--)
9.4JSP指令
<% @ page args...%>
部分指令应用
-
错误页面定制
1.<%@ page errorPage="error/500.jsp" %> <% int x=1/0; %>
这是一个500错误
这error/500.jsp中指定500的错误页面<html> <head> <title>Title</title> </head> <body> <img src="../img/500.png" alt="500"> </body> </html>
2.也可以在web.xml中指定error-page配置
500
/error/500.jsp
-
<%@include page=.../>的使用,实际是一个网站的多个页面可以共享html结构
- 在common下的footer.jsp(尾部共享)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <h1>我是footer</h1>
- 在common下的header.jsp(头部共享)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <h1>我是Header</h1>
<%--会将两个页面合二为一--%> <%@ include file="common/header.jsp"%> <h2>网页主体</h2> <%@include file="common/footer.jsp"%>
-
也可以使用jsp标签体
<jsp: args...><%--jsp标签体--%> <%--会拼接页面,本质还是三个jsp--%> <jsp:include page="common/header.jsp"/> <h2>网页主体</h2> <jsp:include page="common/footer.jsp"/>``
-
4和3的区别
可以看
E:\java-idea\ideaIU_2021.2.3_Portable\ideaIU_2021.2.3_Portable\bin\IdeaConfig\system\tomcat\fed2f09e-c496-4018-b279-fdb23ad0c0c6\work\Catalina\localhost\peng\org\apache\jsp
下的文件可以看出 前者将三个jsp变为了一个html结构
后者仍然是三个jsp,只是在其中进行了调用
9.5大内置对象
- PageContext //存东西
- Request //存东西
- Response
- Session //存东西
- Application (ServletContext) // 存东西
- config (ServletConfig)
- out 输出
- page 几乎不用
- exception 异常
9.5.1 PageContext,Request,Session,Application存东西的区别
%
pageContext.setAttribute("name1","卢鹏一号");
//保存中的数据只在一个页面有效
request.setAttribute("name2","卢鹏二号");
//保存的数据只在一次请求中有效,求情转发也会携带这个数据
session.setAttribute("name3","卢鹏三号");
//保存到数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","卢鹏四号");
//保存的数据只在服务器中有效,从打开浏览器到关闭浏览器
%>
- 从pagecontext中取值
//从pageContext取出,我们通过寻找方式来
//从底层到高层(作用域)
String name1=(String) pageContext.findAttribute("name1");
String name2=(String)pageContext.findAttribute("name2");
String name3=(String)pageContext.findAttribute("name3");
String name4=(String)pageContext.findAttribute("name4");
String name5=(String)pageContext.findAttribute("name5");
String name6=(String)pageContext.findAttribute("name6");
<%--采用EL表达式输出 ${}}--%>
<h1>取出的值为</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name6}</h3><%--不存在--%>
<h3><%=name5%></h3>
这里用el表达书输出,如果该变量对应的值不存在,则不会输出。
但是当我们用传统方式输出,如果该变量对应的值不存在则默认输出为null
-
request:客户端向服务器发送请求,产生的数据客户看完就没用了。比如:新闻,客户看完没用
-
session:客户端向服务端发送请求,产生的数据,用户用完一会还有用。比如:购物车
-
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据
9.6 JSP标签,JSTL标签,EL表达式
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api -->
<dependency>
<!--JSTL表达式的依赖-->
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<!--standard标签库-->
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
-
EL表达式:${}
- 获取数据
- 执行运算
- 获取web开发的常用对象
- 调用java方法
-
JSP标签
<%--jsp.include--%>
<%--跳转页面标签--%>
<jsp:forward page="/JspTag2.jsp">
<jsp:param name="Value1" value="value1"/>
<jsp:param name="Value2" value="value2"/>
<%--再转发的适合可以携带参数,<jsp:param name="" value=""/>--%>
</jsp:forward>
- JSTL表达式
需要在pom.xml中添加:<dependency> <groupId>org.glassfish.web</groupId> <artifactId>jakarta.servlet.jsp.jstl</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-spec</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-impl</artifactId> <version>1.2.5</version> </dependency>
JSTL标签库的使用就是为了弥补HTML标签的不足,他自定义了许多标签,可以供我们使用,标签的功能和java代码一样。具体可参照 菜鸟
- 核心标签(部分)
- 格式化标签
- SQL标签
- XML标签
JSTL标签使用步骤
- 引入对应的taglib
- 使用其中的方法
- 在Tomcat中也需要引入-jsp的包,否则会报错:JSTL解析错误
<body>
<h3>if测试</h3>
<hr>
<form action="ccrmif.jsp" method="get">
<%--EL表达式 获取表单中的数据
${param.参数名}
--%>
<input tyep="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断提交的用户名是管理员则提交成功--%>
<%--
java代码实现
if(request.getParameter("name").equals("admin")) {
out.print("登录成功");
--%>
<c:if test="${param.username=='admin'}" var="isadmin" >
<c:out value="管理员欢迎您"></c:out>
</c:if>
<c:out value="${isadmin}"></c:out>
</body>
本节用Tomcat10出现问题,无法解决,不会!!! 所以直接跳到下一节JavaBean
10.JavaBean
实体类
JavaBean有特定的写法:
- 必须要有一个无参构造
- 属性必须私有化
- 必须有对应的get/set()方法
一般用来做数据库的映射 ORM;
ORM:对象关系映射
- 表->类
- 字段->属性
- 行记录->类的对象
jsp使用javaBean:
11.MVC三层架构
什么是MVC:Model vies Controlleer 模型,视图,控制器.
11.1早些年的网站架构:
用户直接访问控制层,控制层直接操作数据库;
servlet-->CRUD-->数据库
弊端:程序十分臃肿,不利于维护。
servlet的代码中:处理请求,响应,视图跳转,处理JDBC,处理业务代码,处理逻辑代码。
架构:没有什么是加一层解决不了的.
调用--JDBC--mysql,Oracle....
11.2 现在MVC三层架构基本流程
- Model
- 业务处理:业务逻辑(Servce)
- 数据持久层:CRUD (Dao)
- View:
- 展示数据
- 提供连接发起Servlet请求(a,form,img...)
- Controller(Servlet)
- 接收用户请求:(req:请求参数,Session信息...)
- 交给业务层处理对应代码
- 控制视图跳转
12.Filter(重点)
Filter:过滤器,用来过滤网站的数据;
- 处理中文乱码
- 登录验证
Filter开发步骤:
-
导包
-
编写过滤器
实现Filter接口,重写对应的几个方法。
//初始化,web服务器启动就已经初始化了,因为要随时等待过滤对象。 @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("已经初始化"); } //Chain:链 /* 1.过滤器中过大所有代码,再过滤特定请求的时候都会执行。 2.必须要让过滤器继续同行,chain.doFilter(request,response); 3. */ @Override 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("CharaterEncdingFilter执行前......"); chain.doFilter(request,response);//让我们的请求继续走,如果不写,程序到这里就被拦截停止了!交接请求响应 /* */ System.out.println("CharaterEncdingFilter执行后......"); } //销毁:web服务器关闭的时候,过滤器会销毁。 @Override public void destroy() { jakarta.servlet.Filter.super.destroy(); System.out.println("已销户"); }
-
在web.xml中配置Filter过滤器。
13.监听器
实现一个监听器的接口;(有n种)
- 编写一个监听器
- 实现监听器的接口
public class OnlineCountListener implements HttpSessionListener { //创建session监听 //一旦创建一个session,就会触发一次这个事件。 @Override public void sessionCreated(HttpSessionEvent se) { ServletContext ctx = se.getSession().getServletContext(); System.out.println(se.getSession().getId());//输出一下session的id,看看输出了几次 Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount"); if(onlineCount==null){ onlineCount=Integer.valueOf(1); }else { int count = onlineCount.intValue(); onlineCount=Integer.valueOf(count+1); } ctx.setAttribute("OnlineCount",onlineCount); } //销毁session监听 //一旦session销毁就会触发这个事件。 @Override public void sessionDestroyed(HttpSessionEvent se) { ServletContext ctx = se.getSession().getServletContext(); Integer onlineCount=(Integer) ctx.getAttribute("OnlineCount"); if(onlineCount==null){ onlineCount=Integer.valueOf(0); }else{ int count = onlineCount.intValue(); onlineCount=Integer.valueOf(count-1); } ctx.setAttribute("OnlineCount",onlineCount); } /* Session销毁: 1.手动销毁:getSession().invalidate(); 2.自动销毁,在web.xml配置过期时间 */ }
- 注册监听器
<!-- 注册监听器--> <listener> <listener-class>listener.OnlineCountListener</listener-class> </listener>
- 看情况是否使用监听器
14.过滤器和监听器的常见应用
监听器:GUI编程中经常使用
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() {
@Override
public void windowOpened(WindowEvent e) {
System.out.println("打开");
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("关闭ing");
System.exit(0);
}
@Override
public void windowClosed(WindowEvent e) {
System.out.println("关闭ed");
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
System.out.println("激活");
}
@Override
public void windowDeactivated(WindowEvent e) {
System.out.println("未激活");
}
});
}
}
案例:用户登录后才能进入主页,用户注销就不能进入主页.
- 用户登录之后,向Session中放入用户数据
- 进入主页的时候判断用户是否已经登录,要求:在过滤器中实现!
HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; if(request.getSession().getAttribute(Constant.User_SESSION)==null){ response.sendRedirect("/error.jsp"); } //传给过滤器链,使其依然能够往下走 chain.doFilter(req,resp); ```
15. JDBC
什么是JDBC:java连接数据库
需要jar包的支持:
- java.sql
- jakarta.sql
- mysql-conneter...连接驱动必须要导入
实验环境搭建
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//配置信息
String url="jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=utf-8";
String username="root";
String password="1094148867g";
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.连接数据库,代表数据库
Connection conn = DriverManager.getConnection(url, username, password);
//3.向数据库发送sql的对象statement:CRUD
Statement statement = conn.createStatement();
//4.编写sql
String sql="select * from users";
//5.执行sql,返回结果集
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();
conn.close();
}
导入数据库依赖
<!--mysql的驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
IDEA中连接数据库
JDBC固定步骤:
- 加载驱动
- 连接数据库,代表数据库
- 先数据库发送sql的对象statement:CRUD
- 编写sql(根据业务,不同的sql)
- 执行sql
- 关闭连接
事务
要么都成功,要么都失败
ACID原则:保证数据安全。
开启事务
关闭事务
事务提交 commit()
事务回滚 rollback()
转账:
A:1000
B:1000
A--100-->B
A:900
B:1100
16. SMBMS(超市订单管理系统)
基本架构模块:
数据库:
项目搭建
- 搭建一个maven项目
- 配置tomcat
- 测试项目是否能够运行
- 导入项目中会遇到的jar包
jakarta.servlet-api,msql驱动, - 创建项目包结构
- 创建实体类
ORM映射:表--类映射 - 编写基础公共类
- 数据库配置文件
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=utf-8 username=root password=1094148867g
- 编写数据库的公共类
//操作数据库的公共类 public class BaseDao { private static String driver; private static String url; private static String username; private static String password; //静态代码块,类加载的时候就初始化了 static{ //通过类加载器读取对应资源 InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties"); Properties properties = new 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 conn=null; try { Class.forName(driver); conn=DriverManager.getConnection(url,username,password); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); } return conn; } //编写查询公共方法 public static ResultSet executeQuery(Connection conn, String sql, Object[] params, ResultSet resultSet, PreparedStatement pre) throws SQLException { //预编译的sql在后面直接执行不用传递sql pre = conn.prepareStatement(sql); for (int i = 0; i < params.length; i++) { //serObject,占位符从1开始,但是我们的数组从0开始。 pre.setObject(i+1,params[i]); } resultSet = pre.executeQuery(); return resultSet; } //编写增删改公共方法 public static int execute(Connection conn,String sql,Object[] params,ResultSet resultSet,PreparedStatement pre ) throws SQLException { pre = conn.prepareStatement(sql); for (int i = 0; i < params.length; i++) { //serObject,占位符从1开始,但是我们的数组从0开始。 pre.setObject(i+1,params[i]); } int updateRows = pre.executeUpdate(); return updateRows; } //释放资源 public static boolean closeResource(Connection conn,Object[] params,ResultSet resultSet,PreparedStatement pre ) { boolean flag = true; if (resultSet != null) { try { resultSet.close(); //垃圾回收 resultSet = null; } catch (SQLException e) { e.printStackTrace(); flag = false; } } if (pre != null) { try { pre.close(); //垃圾回收 pre = null; } catch (SQLException e) { e.printStackTrace(); flag = false; } } if (conn != null) { try { conn.close(); //垃圾回收 conn = null; } catch (SQLException e) { e.printStackTrace(); flag = false; } } return flag; } }
- 编写字符编码过滤器
public class CharacterEncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); chain.doFilter(request,response); } @Override public void destroy() { Filter.super.destroy(); } }
<!--字符编码过滤器--> <filter> <filter-name>CharaterEncodingFilter</filter-name> <filter-class>com.peng.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharaterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
- 导入静态资源
登录功能实现
-
编写前端页面
-
设置首页
<!--设置欢迎页面--> <welcome-file-list> <welcome-file>login.jsp</welcome-file> </welcome-file-list>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>系统登录 - 超市订单管理系统</title> <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath }/css/style.css" /> <script type="text/javascript"> /* if(top.location!=self.location){ top.location=self.location; } */ </script> </head> <body class="login_bg"> <section class="loginBox"> <header class="loginHeader"> <h1>超市订单管理系统</h1> </header> <section class="loginCont"> <form class="loginForm" action="${pageContext.request.contextPath }/login.do" name="actionForm" id="actionForm" method="post" > <div class="info">${error }</div> <div class="inputbox"> <label for="user">用户名:</label> <input type="text" class="input-text" id="userCode" name="userCode" placeholder="请输入用户名" required/> </div> <div class="inputbox"> <label for="mima">密码:</label> <input type="password" id="userPassword" name="userPassword" placeholder="请输入密码" required/> </div> <div class="subBtn"> <input type="submit" value="登录"/> <input type="reset" value="重置"/> </div> </form> </section> </section> </body> </html>
- 编写dao层得到用户登录的接口
public interface UserDao { //得到登录的用户 public User getLoginUser(Connection conn,String userCode) throws SQLException; }
- 编写dao接口的是实现类
public class UserDaoImpl implements UserDao { @Override public User getLoginUser(Connection conn, String userCode){ PreparedStatement pre=null; ResultSet res=null; User user=null; if(conn!=null) { String sql = "select * from smbms_user where userCode=?"; Object[] params = {userCode}; try { res = BaseDao.executeQuery(conn, sql, params, res, pre); if(res.next()){ user=new User(); user.setId(res.getInt("id")); user.setUserCode(res.getString("userCode")); user.setUserName(res.getString("userName")); user.setUserPassword(res.getString("userPassword")); user.setGender(res.getInt("gender")); user.setBirthday(res.getDate("birthday")); user.setPhone(res.getString("phone")); user.setAddress(res.getString("address")); user.setUserRole(res.getInt("userRole")); user.setCreatedBy(res.getInt("createBy")); user.setCreationDate(res.getDate("creationDate")); user.setModifyBy(res.getInt("modifyBy")); user.setModifyDate(res.getDate("modifyDate")); } BaseDao.closeResource(null,res,pre); } catch (SQLException e) { e.printStackTrace(); } } return user; } }
- 业务层接口
//用户登录 public User login(String userCode,String password);
- 业务层实现类
public class UserServiceImpl implements UserService{ //业务层都会调用dao层,所以要引入dao层; private UserDao userDao; public UserServiceImpl(){ userDao=new UserDaoImpl(); } @Override public User login(String userCode, String password) { Connection conn=null; User user=null; conn= BaseDao.getConnection(); try { //通过业务层调用对应的具体的数据库操作 user = userDao.getLoginUser(conn, userCode); } catch (SQLException e) { e.printStackTrace(); }finally { BaseDao.closeResource(conn,null,null); } return user; }
- 编写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/fram.jsp"); }else{ //查无此人,无法登录,转发会登录界面,顺带提示它,用户名或者密码错误 req.setAttribute("error","用户名或者密码不正确"); req.getRequestDispatcher("login.jsp").forward(req,resp); } }
- 注册Servlet
<servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.peng.servlet.user.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login.do</url-pattern> </servlet-mapping>
- 测试运行正常
登录功能的优化
注销功能:
思路:移除Session,返回登录页面
public class LoginoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//移除用户Session
req.getSession().removeAttribute(Constants.USER_SESSION);
resp.sendRedirect("/login.jsp");//注销后返回登录页面
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
注册xml
<servlet>
<servlet-name>LoginoutServlet</servlet-name>
<servlet-class>com.peng.servlet.user.LoginoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginoutServlet</servlet-name>
<url-pattern>/jsp/logout.do</url-pattern>
</servlet-mapping>
登录拦截优化。
思路:使用过滤器
注销(退出)用户后,避免用户通过登录路径直接登录到界面。
编写一个过滤器并注册
public class SysFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request1 = (HttpServletRequest) request;
HttpServletResponse response1 = (HttpServletResponse) response;
//过滤器,从Seesion中获取用户
User user = (User)request1.getSession().getAttribute(Constants.USER_SESSION);
if(user==null){//已经被移除或者注销了,或者未登录
response1.sendRedirect("/smbms/error.jsp");
}else{
chain.doFilter(request,response);
}
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
<!-- 用户登录拦截-->
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>com.peng.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/jsp/*</url-pattern>
</filter-mapping>
密码修改
- 导入前端素材
<li ><a href="${pageContext.request.contextPath }/jsp/bill.do?method=query">订单管理</a></li>
<li><a href="${pageContext.request.contextPath }/jsp/provider.do?method=query">供应商管理</a></li>
<li><a href="${pageContext.request.contextPath }/jsp/user.do?method=query">用户管理</a></li>
<li><a href="${pageContext.request.contextPath }/jsp/pwdmodify.jsp">密码修改</a></li>
<li><a href="${pageContext.request.contextPath }/jsp/logout.do">退出系统</a></li>
- 写项目建议从底层往上写(上一层会调用下一层)
基本思路:根据用户id修改对应密码。service层调用前端传过来的密码与后台表中密码对比,servlet层就是拿到前端的数据。
- UersDao接口
//修改当前用户密码
public int updatePwd(Connection con,int id,int password) throws SQLException;
- UserDaoImpl
//修改当前用户密码
@Override
public int updatePwd(Connection conn, int id, int password) throws SQLException {
PreparedStatement pre=null;
int execute=0;
if(conn!=null) {
String sql = "update smbms_user set userPassword =? where id=?";
Object params[] = {password, id};
execute = BaseDao.execute(conn, sql, params, pre);
BaseDao.closeResource(null, null, pre);
}
return execute;
}
- UserService层
//根据用户id修改密码
public boolean updatePwd(int id, int password) throws SQLException;
- UserService层实现类
//根据用户id修改密码
@Override
public boolean updatePwd(int id, int password){
Connection conn=null;
boolean flag=false;
//修改密码
try {
conn = BaseDao.getConnection();
if(userDao.updatePwd(conn,id,password)>0){
flag=true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
BaseDao.closeResource(conn,null,null);
}
return flag;
}
- 记得实现复用,需要提取出方法
@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);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
public void updatePwd(HttpServletRequest req, HttpServletResponse resp){
//从Session里面拿ID;
Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
//从前端获取新密码(request)
String newPassword = req.getParameter("newpassword");
//排错,是否有拿到密码,从前端中
System.out.println("UserServlet:"+newPassword);
if(attribute!=null && !StringUtils.isNullOrEmpty(newPassword)){
UserService userService = new UserServiceImpl();
boolean flag=false;
try {
//pojo的user实现类id属性是long类型。
flag = userService.updatePwd((int) ((User) attribute).getId(), newPassword);
if(flag){
req.setAttribute("message","修改密码成功。请退出使用新密码");
//密码修改成功移除当前Session
req.getSession().removeAttribute(Constants.USER_SESSION);
}else{
//修改失败
req.setAttribute("message","修改密码失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
else{
req.setAttribute("message","新密码有问题");
}
try {
req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
-
注册Servlet
servlet-mapping是根据前端的跳转地址而定的。
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.peng.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.83</version>
</dependency>
- 后台代码修改
//修改密码
public void updatePwd(HttpServletRequest req, HttpServletResponse resp){
//从Session里面拿ID;
Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
//从前端获取新密码(request)
String newPassword = req.getParameter("newpassword");
//排错,是否有拿到密码,从前端中
System.out.println("UserServlet:"+newPassword);
if(attribute!=null && !StringUtils.isNullOrEmpty(newPassword)){
UserService userService = new UserServiceImpl();
boolean flag=false;
try {
//pojo的user实现类id属性是long类型。
flag = userService.updatePwd((int) ((User) attribute).getId(), newPassword);
if(flag){
req.setAttribute("message","修改密码成功。请退出使用新密码");
//密码修改成功移除当前Session
req.getSession().removeAttribute(Constants.USER_SESSION);
}else{
//修改失败
req.setAttribute("message","修改密码失败");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
else{
req.setAttribute("message","新密码有问题");
}
try {
req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//验证旧密码,Session中的user密码验证
public void pwdmodify(HttpServletRequest req, HttpServletResponse resp){
//1. 拿到用户密码
Object attribute = req.getSession().getAttribute(Constants.USER_SESSION);
String oldpassword=req.getParameter("oldpassword");
//万能的map :结果集
HashMap<String, String> resultMap = new HashMap<>();
if(attribute==null){//Session失效或者过期了
resultMap.put("result","sessionerror");
}
else if(StringUtils.isNullOrEmpty(oldpassword)){//输入的密码为空
resultMap.put("result","error");
}else{
String userPassword = ((User) attribute).getUserPassword();//Session中用户的密码
if(oldpassword.equals(userPassword)){
resultMap.put("result","true");
}else{
resultMap.put("result","false");
}
}
try {
resp.setContentType("application/json");//设置文本类型,返回json值
// resp.setContentType("text/html");
// resp.setContentType("text/javascript");与这些类似,限定格式。
PrintWriter writer = resp.getWriter();
//JSONArray 阿里巴巴的JSON工具类,转换格式
/*
将:
resultMap=["reslut","sessionerror","result","error"]
转换为:
Json格式={key:value}
*/
writer.write(JSONArray.toJSONString(resultMap));
//刷新防止溢出
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
用户管理实现
要实现一下的用户管理页面:
按一下流程图实施:
- 导入分页的工具类
public class PageSupport {
//当前页码-来自与用户输入
private int currentPageNo=1;
//总数量(表)
private int totalCount=0;
//页面容量
private int pageSize=0;
//总页数-totalCount/pageSize(+1)
private int totalPageCount=1;
public int getCurrentPageNo(){return currentPageNo;}
public void setCurrentPageNo(int currentPageNo){
if(currentPageNo>0){
this.currentPageNo=currentPageNo;
}
}
public int getTotalCount(){return totalCount;}
//OOP(面向对象) 三大特性:封装(属性私有,get/set,在set中限定一些不安全的情况),继承,多态
public void setTotalCount(int totalCount){
if(totalCount>0){
this.totalCount=totalCount;
//设置总页数
this.setTotalPageCountByRs();
}
}
public int getPageSize(){return pageSize;}
public void setPageSize(int pageSize){
if(pageSize>0){
this.pageSize=pageSize;
}
}
public int getTotalPageCount(){return totalPageCount;}
public void setTotalPageCount(int totalPageCount){this.totalPageCount=totalPageCount;}
public void setTotalPageCountByRs(){
if(this.totalCount % this.pageSize==0){
this.totalPageCount=this.totalCount/this.pageSize;
}else if(this.totalCount % this.pageSize>0){
this.totalPageCount=this.totalCount/this.pageSize+1;
}else{
this.totalPageCount=0;
}
}
}
- 用户列表页面导入
userlist.jsp
用户数量获取
- UserDao
//根据用户名或者用户角色查询用户总数 public int getUserCount(Connection connection,String username,int userRole) throws SQLException;
- UserDaoImpl
@Override public int getUserCount(Connection connection, String username,int userRole) throws SQLException { PreparedStatement pre=null; ResultSet rs=null; int count=0; if(connection!=null){ /* 在查询用户数量时,根据前端页面提供的信息可以看出有多种查询方法,根据用户名查询,根据用户角色 查询,或者直接查询所有,1.而且查询是从多个表中查询的,所以这里要用到多表连接查询操作。 2.又因为在查表时有多种查询条件,要用到不同的sql语句,但由于这些语句又大部分相似,则可以用字符串 拼接的方法来根据不同条件只需要改变查询条件即可 3.这里的用户名查询可以使用到模糊查询的方法,在like后面,但是不能直接在sql语句中写 % ? % 这样的形式出现在sql中,所以可以创建一个List数组,将所需参数传入,根据不同查询条件 来添加模糊查询。最后在将list数组变为字符串进行查询操作。 */ StringBuffer sql=new StringBuffer(); sql.append("select count(1) as count from smbms_user u,smbms_role r where u.userRole=r.id"); List<Object> list = new ArrayList<>(); if(!StringUtils.isNullOrEmpty(username)){ sql.append(" and u.userName like ?"); list.add("%"+username+"%");//index:0 } if(userRole>0){ sql.append(" and u.userRole=?"); list.add(userRole);//index:1 } //怎么把list转换为数组 Object[] params=list.toArray(); rs=BaseDao.executeQuery(connection,sql.toString(),params,rs,pre); if(rs.next()){ count=rs.getInt("count");//从结果集中获取最终的数量 } BaseDao.closeResource(null,rs,pre); } return count; }
- UserService
//查询记录数 public int getUserCount(String username,int userRole);
- UserServiceImpl
//查询记录数 @Override public int getUserCount(String username, int userRole) { Connection connection = null; int count=0; try { connection=BaseDao.getConnection(); count=userDao.getUserCount(connection,username,userRole); } catch (SQLException e) { e.printStackTrace(); }finally { BaseDao.closeResource(connection,null,null); } return count; }
获取用户列表
- userdao
//通过条件查询获取用户列表 public List<User> getUserList(Connection connection,String username,int userRole,int currentPageNo,int pageSize)throws Exception;
- userdaoImpl
@Override public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception { PreparedStatement pre=null; ResultSet rs=null; List<User> userlist=new ArrayList<>(); if(connection!=null){ StringBuffer sql=new StringBuffer(); sql.append("select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r whrer u.userRole=r.id"); List<Object> list=new ArrayList<>(); if(!StringUtils.isNullOrEmpty(userName)){ sql.append(" and u.username like ?"); list.add("%"+userName+"%"); } if(userRole>0){ sql.append(" and u.userRole =? "); list.add(userRole); } sql.append(" order by creationDate DESC limit ?,?"); /* 当前在数据库中,分页使用 limit startIndex,pageSize;总数 当前页起始序号=(当前页-1)*页面大小 0,5 1 0 01234 5,5 2 5 56789 10,5 3,10 10~14 */ currentPageNo=(currentPageNo-1)*pageSize; list.add(currentPageNo); list.add(pageSize); Object[] params=list.toArray(); rs=BaseDao.executeQuery(connection,sql.toString(),params,rs,pre); while(rs.next()){ User _user=new User(); _user.setId(rs.getInt("id")); _user.setUserRole(rs.getInt("userRole")); _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.setUserRoleName(rs.getString("userRoleName")); userlist.add(_user); } BaseDao.closeResource(null,rs,pre); } return userlist; }
- userService
//根据条件查询用户列表 public List<User> getUserList(String queryUserName,int queryUserRole,int currentPageNo,int pageSize);
- userServiceImpl
@Override 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; }
获取角色操作
为了我们职责统一,可以把角色的操作单独放在一个包中,和POjO类对应。
- RoleDao
public interface RoleDao { //获取角色列表 public List<Role> getRoleList(Connection connection) throws Exception; }
- RoleDaoImpl
public class RoleDaoImpl implements RoleDao{ //获取角色列表 @Override public List<Role> getRoleList(Connection connection) throws Exception { PreparedStatement pre=null; ResultSet rs=null; ArrayList<Role> rolelsit=new ArrayList<Role>(); if(connection!=null){ String sql="select * from smbms_role"; Object[] params={}; rs= BaseDao.executeQuery(connection,sql,params,rs,pre); while(rs.next()){ Role _role = new Role(); _role.setId(rs.getInt("id")); _role.setRoleName(rs.getString("roleName")); _role.setRoleCode(rs.getString("roleCode")); rolelsit.add(_role); } BaseDao.closeResource(null,rs,pre); } return rolelsit; } }
- RoleService
public interface RoelService { //获取角色列表 public List<Role> getRoleList(Connection conn) throws Exception; }
- RoelServiceImpl
public class RoleServiceImpl implements RoelService{ /* 引入Dao */ private RoleDao roleDao; public RoleServiceImpl(){ roleDao=new RoleDaoImpl(); } @Override public List<Role> getRoleList(Connection conn) { Connection connection=null; List<Role> roleList=null; try { connection = BaseDao.getConnection(); roleList= roleDao.getRoleList(connection); } catch (Exception e) { e.printStackTrace(); } BaseDao.closeResource(conn,null,null); return roleList; } }
事务开启
- 添加事务注解
@Transactional - 在jdbc配置类中添加事务管理
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
- 在service层添加事务管理
@Transactional
public interface BookService {
/**
* 保存
* @param book
* @return
*/
public boolean save(Book book);
/**
* 更新
* @param book
* @return
*/
}
...
标签:web,String,int,req,基本概念,null,public,out
From: https://www.cnblogs.com/tkyd/p/17343458.html