JavaWeb开发

JavaWeb

web开发

  • 网页开发

  • 静态web

    • html,css
  • 动态web

    • 数据库交互
    • 常用技术栈:servlet,ASP,PHP

在java中,动态web资源开发的技术统称为JavaWeb

web应用程序

是一种可以通过Web访问的应用程序

静态web

动态web

  • 数据持久化
  • 可以做用户差异化

web服务器

ASP

  • ASP即Active Server Pages,是Microsoft公司开发的服务器端脚本环境,可用来创建动态交互式网页并建立强大的web应用程序。
  • 在html中嵌入VB脚本,ASP+COM;
  • 在ASP开发,基本页面代码量大,逻辑混乱
  • C#
  • IIS

JSP/Servlet

Tomcat

启动关闭

dns查询步骤

网站结构

HTTP

http协议簇

1、HTTP简介

HTTP(超文本传输协议),它是一种请求/响应式的协议,客户端与服务器建立连接后,就可以向服务器发送请求,这种请求被称为HTTP请求,服务器端收到请求后会做出响应,称为HTTP响应,客户端与服务器端在HTTP下的交互过程如图所示。
img

2、HTTP1.0和HTTP2.0

(1) HTTP1.0
客户端与服务器连接后,只能发送一个请求,断开连接。
(2) HTTP2.0
客户端与服务器连接后,发送N个请求,断开连接。

3、HTTP请求消息

一个完整的请求消息是由请求行请求头实体三部分组成,每部分的功能各不相同。

1、请求行

HTTP请求行包括几个部分,请求方式,资源路径…
HTTP的8种请求方式:

  • GET

  • POST

  • HEAD

  • PUT

  • DELETE

  • TRACE

  • CONNECT

  • OPTIONS
    其中最常用的两种方式是POST和GET

  • GET

  • POST

    • 传输数据大小没有限制
    • 安全
    • 不会在URL地址栏显示参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET在浏览器回退时是无害的,而POST会再次提交请求。

GET产生的URL地址可以被Bookmark,而POST不可以。

GET请求会被浏览器主动cache,而POST不会,除非手动设置。

GET请求只能进行url编码,而POST支持多种编码方式。

GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。

GET请求在URL中传送的参数是有长度限制的,而POST么有。

对参数的数据类型,GET只接受ASCII字符,而POST没有限制。

GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。

GET参数通过URL传递,POST放在Request body中。

2、请求消息头

请求消息头主要用于向服务器端传递附加消息,例如,客户端可以接收的数据类型、压缩方法、语言以及发送请求的超链接所属页面的URL地址等消息。

1
2
3
4
5
6
Accept: 告诉浏览器,它所支持的数据类型
Accept-Encoding: 支持那种编码格式
Accept-Language: 指定客户端期望服务器返回哪个国家语言文档
Host:指定资源所在的主机名和端口号
Referer:常被网站管理人员用来查看网站的访问者是如何导航进入网站的。也可以用于网站的防盗链
Authorization:Proxy-Authorization:if-Match:if-Modified-Since:Range:if-RangeMax-Forward:User-Agent:

4、响应消息

当服务器收到浏览器的请求后,会回送响应给客户端。一个完整的响应消息主要包括响应状态行响应消息头实体内容

1、响应状态行

它包括三个部分,分别是HTTP版本,表示成功还是错误的状态码和对状态码进行描述的文本信息
例如:

1
HTTP/1.1 200 OK

响应状态码

状态码由3位数组成,第1个数定义了响应的类别,后面两位没有具体的分类

1
1XX:表示请求已接收,需要继续处理2XX:表示请求已成功被服务器接收、理解,并接收3XX:请求重定向4XX:客户端的请求有错误5XX:服务器端出现错误

400(错误请求)服务器不理解请求的语法 参数错误
401表示发送的请求需要有通过HTTP认证的认证信息 没有认证
403(禁止)服务器拒绝请求 无权限
404(未找到)服务器找不到请求网页 找不到
500 服务器错误
503 表示服务器处于停机维护或超负载,无法处理请求

2、响应消息头

向客户端传递附加消息,包括服务程序名、被请求资源需要的认证方式、客户端请求资源的最后修改时间、重定向地址等消息。

1
Location:通知客户端获取请求文档新地址Refresh:告诉浏览器自动刷新的时间,以秒为单位Connection:告诉浏览器,请求完成是断开还是保证连接

Maven

架构管理工具

核心思想:约定大于配置

  • 遵守约束,不要违反

Maven会约束代码规范

环境配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
| Default: ${user.home}/.m2/repository localRepository 指定包下载的位置
-->
<!-- 本地仓库位置 -->
<localRepository>D:\java\m2</localRepository>
...
<!-- 远程仓库位置 -->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>

镜像配置

本地仓库

IDEA项目创建

创建项目

可以使用idea开发工具构建,创建maven工程/web工程

创建完,需要配置坐标pom.xml文件

  • 关于idea默认使用自带的home变量

结束

一个干净的maven项目

标记文件夹

或者在project struct选择目录标记

配置Tomcat

创建配置文件

解决警告

maven命令

1
2
3
4
5
mvn clean   # 清理编译项目
mvn compile # 编译项目
mvn test # 测试项目
mvn package # 项目打包
mvn install # 安装到仓库中

pom配置文件

maven jar导入

搜索maven仓库,例如spring,并复制粘贴dependency,会自动导入jar以及所依赖的jar包

资源导出问题

搜索maven资源导出问题,copybuild代码到pom里面

maven生成目录树

Servlet

Servlet的工作过程

当用户通过 URL 发出一个请求时,这些 Java servlet 类就将之转换成一个 HttpServletRequest,并发送给 URL 所指向的目标。当服务器端完成其工作时,Java 运行时环境(JRE)就将结果包装在一个 HttpServletResponse 中,然后将原 HTTP 响应送回给发出该请求的客户机。

在与 Web 应用程序进行交互时,通常会发出多个请求并获得多个响应。所有这些都是在一个会话语境中,Java 语言将之包装在一个 HttpSession 对象中。在处理响应时,您可以访问该对象,并在创建响应时向其添加事件。它提供了一些跨请求的语境。

Servlet工作原理及架构

  • servlet具体的实现类用我们自己编写

    • 接收并处理请求

    • 返回响应信息

当Web服务器接收到一个HTTP请求时,它会先判断请求内容——如果是静态网页数据,Web服务器将会自行处理,然后产生响应信息;如果牵涉到动态数据,Web服务器会将请求转交给Servlet容器。此时Servlet容器会找到对应的处理该请求的Servlet实例来处理,结果会送回Web服务器,再由Web服务器传回用户端

针对同一个Servlet,Servlet容器会在第一次收到http请求时建立一个Servlet实例,然后启动一个线程。第二次收到http请求时,Servlet容器无须建立相同的Servlet实例,而是启动第二个线程来服务客户端请求。所以多线程方式不但可以提高Web应用程序的执行效率,也可以降低Web服务器的系统负担

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1. 客户端 向Servlet容器(Tomcat)发出Http请求;

2. Servlet容器接收客户端的请求;

3. Servlet容器创建一个HttpRequest对象,将客户端请求的信息封装到这个对象中;

4. Servlet容器创建一个HttpResponse对象;

5. Servlet容器调用HttpServlet对象的service方法,把HttpRequest对象与HttpResponse对象作为参数传给 HttpServlet对象;

6. HttpServlet调用HttpRequest对象的有关方法,获取Http请求信息;

7. HttpServlet调用HttpResponse对象的有关方法,生成响应数据;

8. Servlet容器把HttpServlet的响应结果传给客户端;

Servlet的生命周期

Http Servlet实现

  • 继承HttpServlet类

    • 重写doget()方法
    • 重写dopost()方法
  • 继承GennerServlet类

  • 实现Servlet类

web.xml配置

servlet标签和servlet mapping成对出现

1
2
3
4
5
6
7
8
9
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.loh.hservlet.HelloServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
  • servlet标签处理当前请求需要使用哪个类进行处理
  • mapping指定浏览器的映射路径

mapping问题

  1. 一个servlet可指定一个映射路径

    1
    2
    3
    4
    <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
    </servlet-mapping>
  2. 一个servlet可指定多个映射路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <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>
  3. 一个servlet可指定通用映射路径

    1
    2
    3
    4
    <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello/*</url-pattern>
    </servlet-mapping>
  4. 可自定义指定前缀、后缀等

    1
    2
    3
    4
    <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/*.do</url-pattern>
    </servlet-mapping>
    • example通配.do

指定了固定映射的mapping优先级最高,当找不到时会走默认处理请求

ServletContext

web容器在启动时会为每个web程序都创建一个对应的

ServletContext对象,代表了当前的web应用

为了解决Servlet程序直接进行IO操作导致效率低下的原因,ServletContext对象也能进行IO

  • 主要用于多个Servlet通过ServletContext对象实现数据共享。

  • 获取Servlet的初始化参数

1.共享数据

提交数据类

1
2
3
ServletContext servletContext = this.getServletContext();
String username = "loh";
servletContext.setAttribute("username",username);

获取数据并输出

1
2
3
4
5
6
ServletContext servletContext = this.getServletContext();
String username = (String) servletContext.getAttribute("username");

resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print(username);

2.获取web参数

web.xml配置参数

1
2
3
4
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>

通过字段获取参数

1
2
3
4
5
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");

PrintWriter printWriter = resp.getWriter();
printWriter.print(url);

3.请求转发

1
2
3
4
5
ServletContext servletContext = this.getServletContext();
// 简短代码
// servletContext.getRequestDispatcher("/hello").forward(req,resp);
RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/hello");//转发的请求路径
requestDispatcher.forward(req,resp);//调用forward实现请求转发

4.资源读取

resource文件夹新建properties

1
2
username=loh
password=123456

处理类从文件流中读取

1
2
3
4
5
6
7
8
9
10
//        获取Servletcontext读取资源转换为输入流
InputStream inputStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");


Properties prop = new Properties();
prop.load(inputStream);
// properties对象从输入流中读取并输出
String user =prop.getProperty("username");
String pwd =prop.getProperty("password");
resp.getWriter().print(user+":"+pwd);

HttpServletResponse

我们再前面已经学过ServletContext(代表整个web应用的一个东西),我们了解到Servlet里面最重要的方法为service方法,service方法里面会有两个参数,为HttpServletRequest(请求),HttpServletResponse(响应)

web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的HttpServletResponse对象;

如果要获取客户端请求过来的参数:找HttpServletRequest

如果要给客户端响应一些信息:找HttpServletResponse

  • 该类继承ServletResponse

负责向浏览器发送数据的方法

(往外写出的方法)

1
2
3
ServletOutputStream getOutputStream() throws IOException;  //写流用这个

PrintWriter getWriter() throws IOException; //写中文用这个,如果用这个写一些东西的时候,会造成字符串损坏或者丢失

负责向浏览器发送响应头的方法

这是ServletResponse里面的方法:

1
2
3
4
void setCharacterEncoding(String var1); //设置响应的编码
void setContentLength(int var1); //设置响应的字符串长度
void setContentLengthLong(long var1); //设置长度
void setContentType(String var1); //设置类型

这是HttpServletResponse里面的方法

1
2
3
4
5
6
7
8
9
10
11
void setDateHeader(String var1, long var2);

void addDateHeader(String var1, long var2);

void setHeader(String var1, String var2);

void addHeader(String var1, String var2);

void setIntHeader(String var1, int var2);

void addIntHeader(String var1, int var2);

响应状态码

1
2
3
4
5
int SC_CONTINUE = 100;  //100是服务器接收到客户端发来的请求的初始部分,并且请客户端继续发送
int SC_OK = 200; //状态ok
int SC_NOT_FOUND = 404; //没有找到
int SC_INTERNAL_SERVER_ERROR = 500; //服务器端错误
int SC_BAD_GATEWAY = 502; //网关出现了问题

Response响应下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//        获取下载文件路径
String resourcePath = "G:\\Loh\\Code\\javaweb-maven\\ServletResponse\\src\\main\\resources\\2.png";
System.out.println("下载文件路径:"+resourcePath);
// 下载的文件名是什么
String fileName = resourcePath.substring(resourcePath.lastIndexOf("\\")+1);
// 头部声明,通知浏览器在下载文件,中文文件名使用URLEncoder.encode编码防止乱码
resp.setHeader("Content-Disposition","attachment;fileName="+fileName);
// 获取下载文件的输入流
FileInputStream in = new FileInputStream(resourcePath);
// 创建缓冲区
int len =0;
byte[] buffer = new byte[1024];
// 获取输出流对象
ServletOutputStream out = resp.getOutputStream();
// 写入缓冲
while ((len = in.read(buffer))!= -1){
out.write(buffer,0,len);
}
// 关闭流
in.close();
out.close();

转发和重定向的区别

HttpServletRequest

方法

验证码实现

实现思路

  • 画笔绘制背景
  • 画笔调用随机数生成方法生成随机数字验证码
  • 浏览器参数设置绘制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//浏览器5秒刷新一次
resp.setHeader("refresh","5");

//在内存中创建图片
BufferedImage Image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
//获取画笔
Graphics2D g = Image.createGraphics();
//设置画笔颜色
g.setColor(Color.WHITE);
//填充背景颜色
g.fillRect(0,0,80,20);

//设置画笔颜色
g.setColor(Color.black);

//设置画笔字体、粗细、字号
g.setFont(new Font("宋体",Font.BOLD,20));

//画笔绘制,绘制坐标
g.drawString(makeNum(),0,20);

//浏览器响应类型参数设置
resp.setContentType("image/jpeg");
//浏览器响应的过期时间,立即过期
resp.setDateHeader("expires",-1);
//响应,缓存控制为不缓存
resp.setHeader("Cache-Control","no-cache");
//不缓存
resp.setHeader("Pragma","no-cache");

//IO写图,格式化类型,从响应对象中输出
boolean jpg_out = ImageIO.write(Image, "jpg", resp.getOutputStream());
}

//随机数生成
private String makeNum(){
Random random = new Random();
String num = random.nextInt(9999999)+"";
StringBuffer stringBuffer = new StringBuffer();
//随机数不足7位时for循环遍历补足
for (int i = 0; i < 7-num.length(); i++) {
stringBuffer.append("0");
}
String s = stringBuffer.toString() + num;
//返回
return num;
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}

表单参数获取

前端提交参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<h1>login</h1>
<div>
<%-- 当前项目路径获取--%>
<form action="${pageContext.request.contextPath}login" method="post">
name:<input type="text" name="username"><br>
password:<input type="password" name="password"><br>
hobby:
<input type="checkbox" name="hobby" value="code">code
<input type="checkbox" name="hobby" value="sing">sing
<input type="checkbox" name="hobby" value="watch movie">movie
<br>
<input type="submit">
<input type="reset">
</form>
</div>
</body>

后端获取

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name =req.getParameter("username");
String pwd =req.getParameter("password");
System.out.println(name);
System.out.println(pwd);

}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}

请求转发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//        设置响应和查询编码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");

// 获取响应输出流
PrintWriter out = resp.getWriter();
// 获取cookie
Cookie[] cookies = req.getCookies();
// 从cookie中获取参数
if (cookies != null){
out.print("上次访问时间");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];

if (cookie.getName().equals("lastLoginTime")){

long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
out.write(date.toLocaleString());
}
}
}else {
out.write("首次访问");
}

// 创建一个Cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
// 设置有效期
cookie.setMaxAge(24*60*60);
// 响应给浏览器一个cookie
resp.addCookie(cookie);
  • cookie内容乱码可以用URLEncoder.encode和decode进行编解码内容

cookie设置path

session

session的两种实现方式

第一种方式的理解:就是把session的id 放在cookie里面(为什么是使用cookies存放呢,因为cookie有临时的,也有定时的,临时的就是当前浏览器什么时候关掉即消失,也就是说session本来就是当浏览器关闭即消失的,所以可以用临时的cookie存放。保存再cookie里的sessionID一定不会重复,因为是独一无二的。),当允许浏览器使用cookie的时候,session就会依赖于cookies,当浏览器不支持cookie后,就可以通过第二种方式获取session内存中的数据资源。

第二种方式的理解:在客户端不支持cookie的情况下使用。为了以防万一,也可以同时使用。

如果不支持cookie,必须自己编程使用URL重写的方式实现。

如何重写URL:通过response.encodeURL()方法

encodeURL()的两个作用

第一个作用:转码(说明:转中文的编码,或者一些其他特殊的编码。就好比如网页的链接中存在中文字符,就会转换成为一些百分号或者其他的符号代替。)

第二个作用:URL后面加入sessionID,当不支持cookie的时候,可以使用encodeURL()方法,encodeUTL()后面跟上sessionID,这样的话,在禁用cookie的浏览器中同时也可以使用session了。但是需要自己编程,只要链接支持,想用session就必须加上encodeURL()。

提示:若想程序中永远支持session,那就必须加上encodeURL(),当别人禁用了cookie,一样可以使用session

session的创建获取和销毁

Session创建

Session获取

Session注销

web.xml中session过期时间配置

使用场景

Cookie和Session的区别

1、数据存放位置不同:

cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、安全程度不同:

cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。

3、性能使用程度不同:

session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。

4、数据存储大小不同:

单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie,而session则存储与服务端,浏览器对其没有限制。

5、会话机制不同

session会话机制:session会话机制是一种服务器端机制,它使用类似于哈希表(可能还有哈希表)的结构来保存信息。

cookies会话机制:cookie是服务器存储在本地计算机上的小块文本,并随每个请求发送到同一服务器。 Web服务器使用HTTP标头将cookie发送到客户端。在客户端终端,浏览器解析cookie并将其保存为本地文件,该文件自动将来自同一服务器的任何请求绑定到这些cookie。

JSP原理

JSP(Java Server Pages)是一种动态网页开发技术。JSP 文件就是在传统的 HTML 文件中插入 Java 代码和 JSP 标签,后缀名为.jsp

JSP 与 PHP、ASP、ASP.NET 等语言类似,都运行在服务端。通常返回给客户端的就是一个 HTML 文件,因此只要有浏览器就能查看 JSP 页面。

JSP 使用 JSP 标签在 HTML 网页中插入 Java 代码,标签通常以<%开头,以%>结束。JSP 标签有多种功能,比如访问数据库和 JavaBean 组件等,还可以在不同的网页之间传递和共享信息。

JSP 是 Servlet 的扩展,我们可以在 JSP 中使用 Servlet 的所有功能。另外,JSP 还提供了一些其他功能,例如 EL 表达式、自定义标签等。

JSP 依赖于 Servlet,用户访问 JSP 页面时,JS 1被翻译成 Servlet 代码,最终,以字符串的形式向外输出 HTML 代码。所以,JSP 只是在 Servlet 的基础上做了进一步封装。

JSP 通过表单获取用户输入的数据、访问数据库或其它数据源生成动态的 Web 内容。

jsp内置对象

语法

指令标识

指令标识主要用于设定整个JSP页面范围内都有效的相关信息,它是被服务器解释并执行的,不会产生任何输出到网页中的内容,也就是说指令标识对客户端浏览器是不可见的。
JSP指令标识的语法格式如下:

1
<%@ 指令名 属性1="属性值" 属性2="属性值"......%>
  • 指令名:用于指定指令名称,在JSP中包含page,include和taglib3条指令。
  • 属性:用于指定属性名称,不同的指令包含不同的属性。一个指令可以设置多个属性,各属性之间用分号隔离。
  • 属性值:用于指定属性值。

1.page指令

这是JSP页面最常用的指令,用于定义整个JSP页面的相关属性,这些属性在JSP被服务器解析成Servlet时会转换为相应的Java程序代码。page指令的语法格式如下:

1
<%@ page 属性1="属性值1" 属性2="属性值2"...%>

page指令提供了language、contentType、import、autoFlush、buffer、errorPage、extends、info、isELIgnored、isErrorSafe和session共13个属性。
下面对常用的属性进行介绍:

2.include指令

通过include指令可以在JSP页面中包含另一个JSP页面,不过该指令是静态包含指令,也就是说被被包含文件中的所有内容会被原样包含到该JSP页面中,即使被包含文件中有JSP代码,在包含时不会被编译执行。使用include指令最终将生成一个文件,所以在被包含和包含的文件中不能有相同名称的变量。
include指令的语法格式如下:

1
<%@ include file="path"%>

该指令只有一个file属性,用于指定要包含文件的路径。该路径是相对路径,也可以是绝对路径,但不可以是通过<%=%>表达式所代表的文件。

3.taglib指令

在JSP文件中,可以通过taglib指令标识声明该页面中所使用的标签库,同时引用标签库,并指定标签的前缀。在页面中引用标签库后,就可以通过前缀来引用标签库中的标签。taglib指令的语法格式如下:

1
<%@ taglib prefix="tagPrefix" uri="tagURI"%>
  • prefix属性:用于指定标签的前缀。该前缀不能命名为jsp、jspx、java、javax、sun、servlet和sunw。
  • uri属性:用于指定标签库文件的存放位置。
    例:在页面中引用JSTL中的核心代码库,实例代码如下:
1
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

脚本标识

JSP表达式

JSP表达式用于向页面中输出信息,其语法格式如下:

1
<% = 表达式%>
  • 表达式:可以是任何Java语言的完整表达式。该表达式的最终运算结果将转换为字符串。
    例:使用JSP表达式在页面中输出信息,示例代码如下:
1
2
3
4
5
6
<%String manager="mr"; %>	<!--定义保存管理员名的变量-->
管理员:<%=manager %> <!--输出结果为:管理员: mr-->
<%="管理员:"+manager %> <!--输出结果为:管理员: mr -->
<%= 7+6 %> <!--输出结果为:13 -->
<%String url="head01.jpg";%><!--定义保存文件名称的变量-->
<img src="images/<%url %>"> <!--输出结果为:<img src="images/head01.jpg">-->

代码片段

所谓代码片段就是在JSP页面中嵌入的Java代码或脚本代码。代码片段将在页面请求的处理期间被执行,通过Java代码可以定义变量或流程控制语句等;而通过脚本代码可以应用JSP的内置对象在页面输出内容、请求处理和响应、访问session会话等。代码片段的语法格式如下:

1
<% Java代码或脚本代码 %>

代码片段的使用比较灵活,他所实现的功能是JSP表达式无法实现的。
例:通过代码片段和JSP表达式在JSP页面上输出九九乘法表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body>
<%
String str="";
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++)
{
str+=j+"x"+i+"="+j*i;
str+="&nbsp;";
}
str+=<"br">;
}
%>
<div>
<ul>
<li id="title">九九乘法表</li>
<li><%=str%><!--输出九九乘法表--></li>
<ul>
</div>
</body>

声明标识

声明表示用于在JSP页面中定义全局的变量或方法。通过声明表示定义的变量和方法可以被整个JSP页面访问,所以通常使用该标识定义整个JSP页面都需要引用的变量或方法。
声明标识的语法格式如下:

1
<%! 声明变量或方法的代码 %>

例:通过声明标识声明一个全局变量和全局方法:

1
2
3
4
5
6
7
<%!
int number = 0;//声明全局变量
int count(){//声明全局方法
number++;//累加number
return number;//返回number的值
}
%>

jsp 9大内置对象

  • PageContext 保存数据
  • Request 保存数据
  • Response
  • Session 保存数据
  • Application【ServletContext】 保存数据
  • config【ServletConfig】
  • out
  • page
  • exception

JSP标签、JSTL标签、EL表达式

EL表达式

  • 获取数据
  • 执行运算
  • 获取web开发的常用对象
  • 调用java
1
${变量名}

JSP标签

JSTL

实现了JSP页面的代码复用。基于标签库原理,重复率较高的代码块支持复用,提高效率。

书写JSP页面时可读性更强。长得像XML,方便前端查看和参与开发。

在应用程序服务器之间提供了一致的接口,最大程度地提高了WEB应用在各应用服务器之间的移植。

简化了JSP和WEB应用程序的开发。

  • 通过jstl标签库弥补jsp使用原生html语法的不足

根据JSTL标签所提供的功能,可以将其分为5个类别。

  • 核心标签

    • ```
      <%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core" %>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127

      - ![](JavaWeb开发/image-20230828202915257.png)

      - **格式化标签**

      - **SQL 标签**

      - **XML 标签**

      - **JSTL 函数**

      ![](JavaWeb开发/image-20230828203838019.png)

      ## jsp不能取值问题

      web.xml头文件版本太低

      # JavaBean

      实体类

      JavaBean特定写法

      - 必须有一个无参构造
      - 属性私有化
      - 必有相应的get/set

      一般用来和数据库字段做映射 ORM:

      ORM:对象关系映射

      - 表----->类
      - 字段---->属性
      - 行记录---->对象

      # MVC架构

      什么是MVC:

      Model 模型

      View 视图

      Controller 控制器



      早期业务架构

      ![](JavaWeb开发\image-20230831155054203.png)

      ![](JavaWeb开发\image-20230831155043558.png)

      MVC架构

      ![](JavaWeb开发\image-20230831155733781.png)

      model

      - 业务处理:业务逻辑模型往往是对数据的处理,如订单和用户信息的修改。(service)

      - 数据持久层:CRUD(Dao)

      View

      - 内容展示:视图是将模型的内容呈现出来
      - 发起请求:用户可以通过对视图的操作进而操作模型,封装的是对数据源Model的显示

      Controller(Servlet处理)

      - 接受请求:(req携带请求参数,session信息等....)
      - 分析业务请求,想业务处理发起处理
      - 控制视图跳转

      ![](JavaWeb开发\image-20230901134011155.png)

      # 过滤器:Filter

      ## 过滤器简介

      filter也称之为过滤器,它是javaWeb三大组件之一(Servlet程序、Listener监听器、Filter过滤器)

      **作用:**既可以对请求进行拦截,也可以对响应进行处理。![](https://img-blog.csdnimg.cn/8f87baaec54244e08a6a33cdcff7be8f.png)

      **常见场景:**权限检查,日记操作、拦截请求、过滤操作、对请求字符设置编码。

      ## filter开发步骤

      ### Maven依赖

      ```xml
      <!-- servlet依赖 -->
      <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
      </dependency>

      <!-- jsp依赖 -->
      <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.3</version>
      <scope>provided</scope>
      </dependency>

      <!-- jstl表达式依赖 -->
      <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
      </dependency>

      <!-- standard标准库依赖 -->
      <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
      </dependency>

      <!-- mysql连接依赖 -->
      <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
      </dependency>

类实现filter接口

导入包名

重写方法

servlet配置

改servlet通过servlet配置的两个路径均可访问,filter过滤servlet路径后,show路径仍为乱码,全路径不乱码

报错

  • 错误日志内容:org.apache.catalina.core.StandardContext.startInternal Context [/16_filter] startup failed due to previous errors

filter类方法重写,所以方法体里自带一段super语句,删除这个语句Tomcat就可以正常运行了。

  • 删除web.xml自动生成的文件头

监听器:listener

开发步骤

实现监听器接口并重写方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.loh.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.net.http.WebSocket;
//实现session监听
public class OnlineCountListener implements HttpSessionListener {
// 创建session时监听
@Override
public void sessionCreated(HttpSessionEvent se) {
// 获取ServletContext
ServletContext sct = se.getSession().getServletContext();
// 从ServletContext中获取字段值
Integer onlineCount = (Integer) sct.getAttribute("OnlineCount");

if(onlineCount==null){
onlineCount =Integer.valueOf(1);
}else {
int count = onlineCount.intValue();
onlineCount=Integer.valueOf(count+1);
}
sct.setAttribute("OnlineCount",onlineCount);
}
//销毁session时监听

@Override
public void sessionDestroyed(HttpSessionEvent se) {
// 获取ServletContext
ServletContext sct = se.getSession().getServletContext();
// 从ServletContext中获取字段值
Integer onlineCount = (Integer) sct.getAttribute("OnlineCount");

if(onlineCount==null){
onlineCount =Integer.valueOf(0);
}else {
int count = onlineCount.intValue();
onlineCount=Integer.valueOf(count-1);
}
sct.setAttribute("OnlineCount",onlineCount);
}
}

注册监听器

1
2
3
4
<!--  注册监听器-->
<listener>
<listener-class>com.loh.listener.OnlineCountListener</listener-class>
</listener>

jsp输出

1
2
3
4
5
6
7
8
9
<html>
<body>
<%--以下为两行jsp表达式--%>
<%@ page pageEncoding="utf-8"%>
<h1>当前<span><%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%></span>人在线</h1>
<h1>当前<span><%=application.getAttribute("OnlineCount")%></span>人在线</h1>
<h2>Hello World!</h2>
</body>
</html>

gui中应用监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.loh.listener;

import javax.swing.*;
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("lets go");
// 面板
Panel panel = new Panel();
// 窗口设置布局tr
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) {

}

@Override
public void windowClosing(WindowEvent e) {

// 退出
System.exit(1);
}

@Override
public void windowClosed(WindowEvent e) {

}

@Override
public void windowIconified(WindowEvent e) {

}

@Override
public void windowDeiconified(WindowEvent e) {

}

@Override
public void windowActivated(WindowEvent e) {

}

@Override
public void windowDeactivated(WindowEvent e) {

}
});
}
}

浏览器登录过滤器项目

描述 该项目共有三 个web资源,三个java类

其中login作为主登录页,主方法类LoginMethod添加seesion字段,并判断字段分辨用户是否登录,并跳转至相应页面

web

success

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--启用过滤器时注销下面的jsp代码--%>
<%--<%--%>
<%-- Object userSession = request.getSession().getAttribute("USER_SESSION");--%>
<%-- if (userSession == null){--%>
<%-- response.sendRedirect("/Login.jsp");--%>
<%-- }--%>
<%--%>--%>
<p><a href="/servlet/logout">注销</a></p>
</body>
</html>

error

1
2
3
4
5
6
7
8
9
10
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>error</h1>
<p><a href="/Login.jsp">返回首页</a></p>
</body>
</html>

login

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>login</h1>
<form action="/servlet/login" method="post">
<input type="text" name="username">
<input type="submit">
</form>
</body>
</html>

java

LoginMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.loh.filter_admin;

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 LoginMethod extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取前端参数
String username = req.getParameter("username");
if (username.equals("admin")){//登录成功
// 设置session字段值给常量USER_SESSION
req.getSession().setAttribute("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);
}
}

LogoutMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.loh.filter_admin;

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 LogoutMethod extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object userSession = req.getSession().getAttribute("USER_SESSION");
if (userSession != null){
req.getSession().removeAttribute("USER_SESSION");
resp.sendRedirect("/Login.jsp");
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

FilterDo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.loh.filter_admin;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FilterDo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;

if (request.getSession().getAttribute("USER_SESSION")==null){
response.sendRedirect("/error.jsp");
}

// 执行过滤
chain.doFilter(req,resp);
}

@Override
public void destroy() {

}
}

注册filter

1
2
3
4
5
6
7
8
9
<filter>
<filter-name>SysFilter</filter-name>
<filter-class>com.loh.filter_admin.FilterDo</filter-class>
</filter>

<filter-mapping>
<filter-name>SysFilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>

JDBC Relearn(复习)

  1. 加载数据库

  2. 连接数据库,代表数据库

  3. 向数据库发送sql对象statement:crud

  4. 编写sql

  5. 执行sql

  6. 关闭连接

1
2
3
4
5
6
7
8
9
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,'李四','123455','sss@qq.com','2021-01-09');

INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`)VALUES(2,'王五','123455','sss@qq.com','2021-01-09');

INSERT INTO users(`id`,`name`,`password`,`email`,`birthday`)VALUES(3,'李四2','123455','sss@qq.com','2021-01-09');

SELECT * FROM users;

statement

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.loh.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class TestJdbc01_Statement {
public static void main(String[] args) throws Exception {
// 配置jdbc信息
String url = "jdbc:mysql://localhost:3306/JDBC_WEB?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";

// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
// statement对象:CRUD
Statement statement = connection.createStatement();
// 编写sql
String sql = "select * from users";
// 执行查询sql
ResultSet rs = statement.executeQuery(sql);

while (rs.next()){
System.out.println("id=" + rs.getObject("id"));
System.out.println("name=" + rs.getObject("name"));
System.out.println("password=" + rs.getObject("password"));
System.out.println("email=" + rs.getObject("email"));
System.out.println("birthday=" + rs.getObject("birthday"));
}
// 关闭连接释放
rs.close();
statement.close();
connection.close();
}
}

增删改

代码与查询基本一致,statement方法以及返回类型不一致,注意,关闭方式相同

1
2
3
4
5
6
//        注释:增删改		
// 增删改使用update
sql ="insert into jdbc_web.users(ID, NAME, PASSWORD, EMAIL, BIRTHDAY) VALUES(4,'DA','12234','21423@QQ.COM','2021-10-28')";
// statement使用update处理sql,该方法返回一个int类型的数(表中受影响的行数)
int i = statement.executeUpdate(sql);
System.out.println("有"+i+"行受影响");

preparestatement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.loh.test;

import java.sql.*;

//使用preparedStatement处理sql
public class TestJdbc02_PrepareStatement {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 配置jdbc信息
String url = "jdbc:mysql://localhost:3306/JDBC_WEB?useUnicode=true&characterEncoding=utf-8";
String username = "root";
String password = "123456";

// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 连接数据库
Connection connection = DriverManager.getConnection(url, username, password);

// 编写sql和占位符
String sql = "insert into jdbc_web.users(id, name, password, email, birthday) VALUES (?,?,?,?,?);";

// 安全sql查询,预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);

// 对占位符进行赋值
preparedStatement.setInt(1,5);
preparedStatement.setString(2,"xaxa");
preparedStatement.setString(3,"54321");
preparedStatement.setString(4,"dasda@qq.com");
preparedStatement.setDate(5,new java.sql.Date(new java.util.Date().getTime()));

int rs = preparedStatement.executeUpdate();

if (rs > 0){
System.out.println("插入成功");
}else {
System.out.println("错误");
}

// 关闭连接释放
preparedStatement.close();
connection.close();
}
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!