JSP
目标:
- 理解
JSP
及JSP
原理- 能在
JSP
中使用 EL表达式 和 JSTL标签- 理解 MVC模式 和 三层架构
- 能完成品牌数据的增删改查功能
# JSP 概述
JSP:全称:Java Server Pages,Java 服务端页面。它是一种动态的网页技术,其中既可以定义HTML
、JS
、CSS
等静态内容,还可以通过Java代码定义动态的内容,简单的理解:JSP = HTML + Java。如下就是jsp
的代码:
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>JSP, Hello World!</h1>
<%
System.out.println("hello, jsp~");
%>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
上面代码h1
标签内容是展示在网页上的,而Java
的输出语句是输出在Idea的控制台里面。
那么,JSP
能做什么呢?比如下图:
上图的用户名是动态展示,也就是谁登录就展示谁的用户名,这个功能我们如果只用servlet
该如何实现呢?在今天的资料里已经提供好了一个LoginServlet
,该servlet
就是实现这个功能的,先将资料中的LoginServlet
拷贝到我们的项目中,并修改登录页面的代码,将登录请求提交到我们的LoginServlet
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
<link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv">
<form action="loginServlet" id="form">
<h1 id="loginMsg">LOGIN IN</h1>
<p>Username:<input id="username" name="username" type="text"></p>
<p>Password:<input id="password" name="password" type="password"></p>
<div id="subDiv">
<input type="submit" class="button" value="login up">
<input type="reset" class="button" value="reset">
<a href="register.html">没有账号?点击注册</a>
</div>
</form>
</div>
</body>
</html>
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
启动服务器并访问登录页面
输入正确的用户名和密码,zhangsan/123
,用户点击登录按钮,就能看到如下图的效果:
当然如果登录的是lisi
,那么在该页面展示的就是lisi, 欢迎您,动态的展示效果就这么实现了。那么LoginServlet
到底是如何实现的呢,我们看下它的源代码:
上面的代码大量使用Response
对象的输出流writer
向页面写HTML
标签的内容,这样我们的代码就显得很繁琐,将来如果展示的效果出现了问题,排查错误会很复杂。那么JSP
相比Servlet
的实现,是如何解决这个问题的呢?在资料中我们也提供了一个login.jsp
页面,该页面也能实现同样的功能,将该页面拷贝到我们的项目webapp
下,同样需要修改login.html
登录页面中表单数据的体积哦啊哦路径:
<form action="login.jsp" id="form">
<h1 id="loginMsg">LOGIN IN</h1>
<p>Username:<input id="username" name="username" type="text"></p>
<p>Password:<input id="password" name="password" type="password"></p>
<div id="subDiv">
<input type="submit" class="button" value="login up">
<input type="reset" class="button" value="reset">
<a href="register.html">没有账号?点击注册</a>
</div>
</form>
2
3
4
5
6
7
8
9
10
11
12
重新启动服务器并进行测试:
下面我们来分析下login.jsp
是如何实现的:
上面代码可以看到里面基本都是HTML
标签,而动态数据使用Java代码进行展示,这样用JSP
实现看起来要比用Servlet
实现顺眼许多。
小结
JSP作用:简化开发,避免在Servlet
中直接输出HTML
标签。
# JSP 快速入门
接下来我们做一个简单的快速入门代码
# 搭建环境
- 创建一个Maven的web项目,项目结构如下
pom.xml
文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.itheima</groupId>
<artifactId>Course</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
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
# 导入 JSP 依赖
在dependencies
标签中导入JSP
的依赖,如下
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
2
3
4
5
6
该依赖的scope
必须设置为provided
,因为tomcat中有这个jar包了,所以在打包的时候我们就不希望将该依赖打进到我们工程的war
包中。
# 创建 JSP 页面
在项目的webapp
下创建JSP
页面
同构上面方式创建一个名为hello.jsp
的页面
# 编写代码
在hello.jsp
页面中书写HTML
标签和Java
代码,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>hello jsp</h1>
<%
System.out.println("hello, jsp~");
%>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
# 快速入门测试
启动服务器并在浏览器地址栏输入http://localhost/course/hello.jsp,我们可以在页面上看到如下内容:
在控制台看到如下内容:
# JSP 原理
我们之前说JSP
就是一个网页,那么在JSP中写HTML
标签,可以理解,那么为什么还可以写Java
代码呢?
这是因为JSP本质上就是一个Servlet。下面我们就聊聊访问JSP
时的流程
- 浏览器第一次访问
hello.jsp
页面 tomcat
会将hello.jsp
转换名为hello_jsp.java
的一个Servlet
tomcat
再将转换的servlet
编译成字节码文件hello_jsp.class
tomcat
会执行该字节码文件,向外提供服务
我们可以到Idea的用户数据目录中找到,我电脑的目录地址为C:\Users\sunyy\.IntelliJIdea2018.2\system\tomcat\Unnamed_JavaWeb_2\work\Catalina\localhost\course\org\apache\jsp
打开hello_jsp.java
文件,我们可以看到里面的源代码,这个hello_jsp
类的定义为:
public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
}
2
3
4
5
从上面的代码可以看到,hello_jsp
继承了名为HttpJspBase
这个类,HttpJspBase
这个类有tomcat
定义,因此我们需要查看tomcat
的源码,其源码已经通过课程资料下发给大家,下面我们就来看下,从源码根目录依次打开java\org\apache\jasper\runtime
,该目录下就有HttpJspBase
类,其类定义为:
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
}
2
3
我们可以看到该类继承了HttpServlet
,那么hello_jsp
这个类就间接继承了HttpServlet
,也就说明hello_jsp
是一个servlet
继续阅读hello_jsp
类的代码,可以看到有一个名为_jspService()
的方法,该方法就是每次访问jsp
时自动执行的方法,和servlet
中的service
方法一样
而在_jspService()
方法中可以看到向浏览器写HTML
标签的代码:
之前我们自己写servlet
时,这部分代码需要由我们自己来写,现在有了jsp
后,由tomcat完成这部分工作。
# JSP 脚本
JSP脚本用于在JSP页面定义Java代码。在之前的入门案例中我们就在JSP页面定义的Java代码就是JSP脚本。
# JSP 脚本分类
JSP脚本有下面三个分类:
<%...%>
:内容会直接放到_jspService()
方法之中<%=...%>
:内容会放到out.print()
中,作为out.print()
的参数<%!...%>
:内容会放到_jspService()
方法之外,被类直接包含
代码演示:
在hello.jsp
中书写
<%
System.out.println("hello, jsp~");
int i = 3;
%>
2
3
4
通过浏览器访问hello.jsp
后,查看转换的hello_jsp.java
文件,i
变量定义在了_jspService()
方法之中
在hello.jsp
中书写
<%="hello"%>
<%=i%>
2
通过浏览器访问hello.jsp
后,查看转换的hello_jsp.java
文件,该脚本的内容被放在了out.print()
中,作为方法参数
在hello.jsp
中书写
<%!
void show() {}
String name = "zhangsan";
%>
2
3
4
通过浏览器访问hello.jsp
后,查看转换的hello_jsp.java
文件,该脚本的内容被放在了成员位置
# JSP 案例
- 案例需求:
使用JSP脚本展示品牌数据
说明:
- 在课程资料中提供了
brand.html
静态页面 - 在该案例中数据不从数据库中查询,先在JSP页面里面写死
- 案例实现:
第一步:将资料中的Brand.java
文件拷贝到项目的com.itheima.pojo
包下
第二步:在项目的webapp
中创建brand.jsp
,并将资料中的brand.html
页面中的内容拷贝过来,brand.jsp
内容如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<input type="button" value="新增"><br>
<hr>
<table border="1" cellspacing="0" width="800">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<tr align="center">
<td>1</td>
<td>三只松鼠</td>
<td>三只松鼠</td>
<td>100</td>
<td>三只松鼠,好吃不上火</td>
<td>启用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td>2</td>
<td>优衣库</td>
<td>优衣库</td>
<td>10</td>
<td>优衣库,服适人生</td>
<td>禁用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td>3</td>
<td>小米</td>
<td>小米科技有限公司</td>
<td>1000</td>
<td>为发烧而生</td>
<td>启用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</table>
</body>
</html>
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
上面的JSP页面中的数据都是写死的数据。
第三步:在brand.jsp
中准备一些数据
<%
// 查询数据库
List<Brand> brands = new ArrayList<>();
brands.add(new Brand(1, "三只松鼠", "三只松鼠", 100, "三只松鼠,好吃不上火", 1));
brands.add(new Brand(2, "优衣库", "优衣库", 200, "优衣库,服适人生", 0));
brands.add(new Brand(3, "小米", "小米科技有限公司", 1000, "为发烧而生", 1));
%>
2
3
4
5
6
7
注意
这里的类是需要导包的。
第四步:将brand.jsp
页面中的table
标签中的数据改为动态获取
<table border="1" cellspacing="0" width="800">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<%
for (int i = 0; i < brands.size(); i++) {
// 获取集合中的 每一个 Brand 对象
Brand brand = brands.get(i);
}
%>
<tr align="center">
<td>1</td>
<td>三只松鼠</td>
<td>三只松鼠</td>
<td>100</td>
<td>三只松鼠,好吃不上火</td>
<td>启用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td>2</td>
<td>优衣库</td>
<td>优衣库</td>
<td>10</td>
<td>优衣库,服适人生</td>
<td>禁用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<tr align="center">
<td>3</td>
<td>小米</td>
<td>小米科技有限公司</td>
<td>1000</td>
<td>为发烧而生</td>
<td>启用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</table>
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
上面的for
循环需要将输出品牌数据的tr
标签包裹起来,这样才能实现循环的效果,将代码改进为
<table border="1" cellspacing="0" width="800">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<%
for (int i = 0; i < brands.size(); i++) {
// 获取集合中的 每一个 Brand 对象
Brand brand = brands.get(i);
%>
<tr align="center">
<td>1</td>
<td>三只松鼠</td>
<td>三只松鼠</td>
<td>100</td>
<td>三只松鼠,好吃不上火</td>
<td>启用</td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<%
}
%>
</table>
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
注意
<%%>
里面写的是Java
代码,而外边写的是HTML
标签
上面代码中的td
标签中的数据都需要是动态的,所以还需要改进:
<%
for (int i = 0; i < brands.size(); i++) {
// 获取集合中的 每一个 Brand 对象
Brand brand = brands.get(i);
%>
<tr align="center">
<td><%=brand.getId()%></td>
<td><%=brand.getBrandName()%></td>
<td><%=brand.getCompanyName()%></td>
<td><%=brand.getOrdered()%></td>
<td><%=brand.getDescription()%></td>
<td><%=brand.getStatus() == 1 ? "启用" : "禁用"%></td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<%
}
%>
</table>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
成品代码:
<%@ page import="java.util.List" %>
<%@ page import="com.itheima.pojo.Brand" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<input type="button" value="新增"><br>
<hr>
<%
// 查询数据库
List<Brand> brands = new ArrayList<>();
brands.add(new Brand(1, "三只松鼠", "三只松鼠", 100, "三只松鼠,好吃不上火", 1));
brands.add(new Brand(2, "优衣库", "优衣库", 200, "优衣库,服适人生", 0));
brands.add(new Brand(3, "小米", "小米科技有限公司", 1000, "为发烧而生", 1));
%>
<table border="1" cellspacing="0" width="800">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<%
for (int i = 0; i < brands.size(); i++) {
// 获取集合中的 每一个 Brand 对象
Brand brand = brands.get(i);
%>
<tr align="center">
<td><%=brand.getId()%></td>
<td><%=brand.getBrandName()%></td>
<td><%=brand.getCompanyName()%></td>
<td><%=brand.getOrdered()%></td>
<td><%=brand.getDescription()%></td>
<td><%=brand.getStatus() == 1 ? "启用" : "禁用"%></td>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
<%
}
%>
</table>
</body>
</html>
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
第五步:在浏览器地址栏输入http://localhost/course/brand.jsp,页面展示效果如下:
# JSP 缺点
通过上面的案例,我们可以看到JSP页面内,既可以定义HTML
标签,又可以定义Java
代码,造成了以下问题:
- 书写麻烦:特别是复杂的页面,既要写
HTML
标签,还要写Java
代码 - 阅读麻烦:上面案例的代码,我们过段时间再来看时还需要花费很长的时间去梳理代码逻辑
- 复杂度高:运行需要依赖各种环境,JRE,JSP容器,JavaEE...
- 占内存和磁盘:JSP会自动生成
.java
和.class
文件 - 调试困难:出错后,需要找到自动生成的
.java
文件进行调试 - 不利于团队协作:前端人员不会
Java
,后端人员不精通HTML
,如果页面布局发生变化,前端工程师对静态页面进行修改,然后交由后端工程师将页面改为JSP页面
由于上述的问题,JSP
已经逐渐退出了历史舞台,以后开发更多的是使用HTML + Ajax来替代。Ajax
是我们后续会重点学习的技术,使用这个技术,前端工程师负责前端页面的开发,而后端工程师只负责后端代码的开发。
下面对JavaWeb
技术的发展进行简单的说明:
- 第一阶段:使用
servlet
实现业务逻辑代码编写,也对页面进行拼接,这种模式我们之前也简单写过 - 第二阶段:随着技术的发展,出现了
JSP
,人们发现JSP
使用起来比Servlet
方便很多,但还要在JSP
中嵌套Java
代码,不利于后期维护 - 第三阶段:使用
Servlet
进行业务逻辑代码开发,而使用JSP
进行数据展示
- 第四阶段:使用
Servlet
进行后端逻辑代码开发,而使用HTML
进行数据展示,但这里存在一个问题,HTML
是静态页面,怎么动态展示数据?可以使用Ajax
技术
既然JSP
已经逐渐退出了历史舞台,为什么还要学习JSP
?原因有两点:
- 有些老的项目可能还在使用
JSP
维护,所以我们需要懂JSP
技术 - 经历这些复杂的过程,可以体现后面使用新技术开发的简单
接下来我们来学习第三阶段的内容,使用EL 表达式和JSTL标签库替换JSP
中的Java
代码
# EL 表达式
# EL 表达式概述
EL(全称Expression Language)表达式语言,用于简化JSP
页面内的Java
代码。
EL表达式的主要作用是获取数据。其实就是从域对象中获取数据,然后将数据展示在页面上。EL表达式的语法也比较简单,${expression}
,例如:${brands}
就是获取域中存储的key
为brands
的数据。
# EL 表达式代码演示
- 定义
Servlet
,在Servlet
中封装一些数据并存储到Request
域对象中并转发到el-demo.jsp
页面。
package com.itheima;
import com.itheima.pojo.Brand;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/demo1")
public class ServletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 准备数据
List<Brand> brands = new ArrayList<>();
brands.add(new Brand(1, "三只松鼠", "三只松鼠", 100, "三只松鼠,好吃不上火", 1));
brands.add(new Brand(2, "优衣库", "优衣库", 200, "优衣库,服适人生", 0));
brands.add(new Brand(3, "小米", "小米科技有限公司", 1000, "为发烧而生", 1));
// 2. 存储到request域中
request.setAttribute("brands", brands);
// 3. 转发到 el-demo.jsp
request.getRequestDispatcher("/el-demo.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
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
注意
此处需要转发,因为转发才可以使用request
对象作为域对象进行数据共享。
- 在
el-demo.jsp
中通过 EL表达式 获取数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${brands}
</body>
</html>
2
3
4
5
6
7
8
9
- 在浏览器的地址栏输入http://localhost/course/demo1,页面效果如下:
# 域对象
JavaWeb
中有四大域对象,分别是:
page
:当前页面有效request
:当前请求有效session
:当前会话有效application
:当前应用有效
EL表达式获取数据,会依次从这四个域中寻找,直到找到为止,这个四个域对象的作用范围如下图所示:
例如:${brands}
,EL表达式获取数据,会先从page
域对象中获取数据,如果没有再到request
域对象中获取数据,如果还没有就再到session
域对象中获取,如果还没有才会到application
中获取数据。
# JSTL 标签
# JSTL 标签概述
JSP标准标签库(JSP Standarded Tag Library),使用标签取代JSP页面上的Java代码,如下就是JSTL标签:
<c:if test="${flag == 1}">
男
</c:if>
<c:if test="${flag == 2}">
女
</c:if>
2
3
4
5
6
上面代码看起来要比JSP中嵌套Java代码舒服,而且前端工程师对标签是特别敏感的,它们看到这段代码是可以看懂的。
JSTL提供了很多标签,如下图:
我们只学习两个最常用的标签,<c:forEach></c:forEach>
和<c:if></c:if>
JSTL使用也比较简单,分为如下步骤:
- 导入坐标
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
2
3
4
5
6
7
8
9
10
- 在JSP页面上引入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- 使用标签
# if 标签
<c:if></c:if>
:相当于if
判断
- 属性:
test
,用于定义条件表达式
<c:if test="${flag == 1}">
男
</c:if>
<c:if test="${flag == 2}">
女
</c:if>
2
3
4
5
6
代码演示:
- 定义一个
servlet
,在该servlet
中向request
域对象中添加键status
,值为1
的数据
package com.itheima;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/demo2")
public class ServletDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 存储数据到request域对象中
request.setAttribute("status", 1);
// 2. 转发到 jstl-if.jsp
request.getRequestDispatcher("/jstl-if.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
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
- 定义
jstl-if.jsp
页面,在该页面使用<c:if></c:if>
标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--
c:if 完成逻辑判断,替换java if else判断语句
--%>
<c:if test="${status == 1}">
启用
</c:if>
<c:if test="${status == 0}">
禁用
</c:if>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
注意
在该页面需要引入JSTL核心标签库:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- 重启服务器,访问http://localhost/course/demo2,页面效果如图:
# forEach 标签
<c:forEach></c:forEach>
:相当于Java中的for
循环,Java中有增强for
循环和普通for
循环,JSTL中的<c:forEach></c:forEach>
也有两种用法
forEach 用法一:
类似与Java中的增强for
循环,<c:forEach></c:forEach>
中的属性如下:
items
:被遍历的容器var
:遍历时产生的临时变量varStatus
:遍历状态对象
如下代码,是从域对象中获取名为brands
数据,该数据是一个集合;遍历该集合,并给该集合中的每一个元素起名为brand
,是Brand
对象。在循环里面使用EL表达式获取每一个Brand
对象的属性值
<c:forEach items="${brands}" var="brand">
<tr align="center">
<td>${brand.id}</td>
<td>${brand.brandName}</td>
<td>${brand.companyName}</td>
<td>${brand.description}</td>
</tr>
</c:forEach>
2
3
4
5
6
7
8
代码演示:
Servlet
还使用之前的名为ServletDemo1
- 定义名为
jstl-foreach.jsp
页面,内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<input type="button" value="新增"><br>
<hr>
<table border="1" cellspacing="0" width="800">
<tr>
<th>序号</th>
<th>品牌名称</th>
<th>企业名称</th>
<th>排序</th>
<th>品牌介绍</th>
<th>状态</th>
<th>操作</th>
</tr>
<c:forEach items="${brands}" var="brand" varStatus="status">
<tr align="center">
<td>${brand.getId()}</td>
<td>${brand.getBrandName()}</td>
<td>${brand.getCompanyName()}</td>
<td>${brand.getOrdered()}</td>
<td>${brand.getDescription()}</td>
<c:if test="${brand.status == 1}">
<td>启用</td>
</c:if>
<c:if test="${brand.status == 0}">
<td>禁用</td>
</c:if>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
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
- 修改
ServletDemo1
,将请求转发至jstl-foreach.jsp
页面
package com.itheima;
import com.itheima.pojo.Brand;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/demo1")
public class ServletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 准备数据
List<Brand> brands = new ArrayList<>();
brands.add(new Brand(1, "三只松鼠", "三只松鼠", 100, "三只松鼠,好吃不上火", 1));
brands.add(new Brand(2, "优衣库", "优衣库", 200, "优衣库,服适人生", 0));
brands.add(new Brand(3, "小米", "小米科技有限公司", 1000, "为发烧而生", 1));
// 2. 存储到request域中
request.setAttribute("brands", brands);
// 3. 转发到 el-demo.jsp
// request.getRequestDispatcher("/el-demo.jsp").forward(request, response);
// 3. for-each演示:将请求转发到jstl-foreach.jsp页面
request.getRequestDispatcher("/jstl-foreach.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
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
- 重启服务器,访问http://localhost/course/demo1,页面效果如下:
forEach 用法二:
类似与Java中的普通for
循环。循环涉及到的属性如下:
begin
:开始数end
:结束数step
:步长
示例代码:从0
循环到10
, 变量名是i
,每次自增1
<c:forEach begin="0" end="10" step="1" var="i">
${i}
</c:forEach>
2
3
# MVC模式和三层架构
MVC模式和三层架构是一些理论的知识,将来我们使用这样的理论进行代码开发会让我们代码维护性和扩展性更好。
# MVC模式
MVC是一种分层开发的模式,其中:
- M:
Model
,业务模型,处理业务 - V:
View
,视图,界面展示 - C:
Controller
,控制器,处理请求,调用模型和视图
控制器(servlet
)用来接收浏览器发送过来的请求,控制器调用模型(JavaBean
)来获取数据,比如从数据库查询数据;控制器获取到数据后交由视图(JSP
)进行数据展示
MVC好处
- 职责单一,互不影响。每个部分做自己的事情,各司其职
- 有利于分工协作
- 有利于组件重用
# 三层架构
三层架构是将我们的项目分成了三个层面,分别是表现层、业务逻辑层、数据访问层。
- 数据访问层:对数据库的数据进行
CRUD
基本操作 - 业务逻辑层:对业务逻辑进行封装,组合数据访问层中基本功能,形成复杂的业务逻辑功能。例如用户注册,我们会先调用数据访问层的
selectByName()
方法判断该用户名是否存在,如果不存在再调用数据访问层的insert()
方法进行数据的添加操作 - 表现层:接收请求,封装数据,调用业务逻辑层,响应数据
而整个流程是,浏览器发送请求,表现层的Servlet
接收请求并调用业务逻辑层的方法进行业务逻辑处理,而业务逻辑层方法调用数据访问层方法进行数据的操作,一次返回到Servlet
,然后Servlet
将数据交由JSP
进行展示。
三层架构的每一层都有特有的包名称:
- 表现层:
com.itheima.controller
或者com.itheima.web
- 业务逻辑层:
com.itheima.service
- 数据访问层:
com.itheima.dao
或者com.itheima.mapper
后续我们还会学习一些框架,不同的框架针对不同层进行封装:
# MVC和三层架构
通过MVC和三层架构的学习,有些人肯定混淆了它们之间的概念,下面我们就来学习下它们有什么区别和练习?
如上图,上半部分时MVC模式,下半部分时三层架构。MVC模式中的C
(控制器)和V
(视图)就是三层架构中的表现层,而MVC模式中的M
(模型)就是三层架构中的业务逻辑层和数据访问层。
可以将MVC模式理解成一个比较大的概念,而三层架构是对MVC模式这种概念的一种架构思想。那么我们后面会以三层架构的思想将不同层的代码写在不同的包下,每一层里功能职责做到单一,将来如果要将表现层的技术换掉,业务逻辑层和数据访问层的代码是不需要发生变化的。
# 案例
需求:完成品牌数据的增删改查操作
这个功能我们之前一直在做,下面我们就用今天学习的所有的内容(包括MVC模式和三层架构)将这个需求做出来。
# 环境准备
环境准备步骤:
创建新模块,引入依赖坐标
创建三层架构的包结构
创建数据库表
tb_brand
创建实体类
Brand
准备
MyBatis
基础环境mybatis-config.xml
BrandMapper.xml
BrandMapper.java
接口
创建工程
创建新的Maven JavaWeb模块,引入坐标。引入坐标环节,我们需要分析出要用到哪些技术,技术确定了,那么需要哪些依赖坐标也就明确了
- 操作数据库,mysql驱动包
- 使用mybatis框架,mybatis依赖包
- 需要使用servlet和jsp,servlet和jsp的依赖包
- 需要使用jstl进行数据展示,jstl的依赖包
pom.xml
内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>com.itheima</groupId>
<artifactId>Course</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--mybatis 依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</project>
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
- 创建包
创建不同的包结构,用来存储不同的类,包结构如下
- 创建品牌表
-- 删除tb_brand表
drop table if exists tb_brand;
-- 创建tb_brand表
create table tb_brand
(
-- id 主键
id int primary key auto_increment,
-- 品牌名称
brand_name varchar(20),
-- 企业名称
company_name varchar(20),
-- 排序字段
ordered int,
-- 描述信息
description varchar(100),
-- 状态:0:禁用 1:启用
status int
);
-- 添加数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
('小米', '小米科技有限公司', 50, 'are you ok', 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.itheima.pojo;
public class Brand {
// id 主键
private Integer id;
// 品牌名称
private String brandName;
// 企业名称
private String companyName;
// 排序字段
private Integer ordered;
// 描述信息
private String description;
// 状态:0:禁用 1:启用
private Integer status;
public Brand() {
}
public Brand(Integer id, String brandName, String companyName, String description) {
this.id = id;
this.brandName = brandName;
this.companyName = companyName;
this.description = description;
}
public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
this.id = id;
this.brandName = brandName;
this.companyName = companyName;
this.ordered = ordered;
this.description = description;
this.status = status;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
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
- 准备MyBatis环境
定义核心配置文件mybatis-config.xml
,并将该文件放到resources
目录下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 起别名 -->
<typeAliases>
<package name="com.itheima.pojo" />
</typeAliases>
<!--
environments:develop配置数据库连接环境信息。
-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--数据库连接信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--加载sql映射文件-->
<!--Mapper代理方式-->
<package name="com.itheima.mapper"/>
</mappers>
</configuration>
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
在resources
下创建放置映射配置文件的目录结构com/itheima/mapper
,并在该目录下创建映射配置文件BrandMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.BrandMapper">
</mapper>
2
3
4
5
# 查询所有
当我们点击index.jsp
页面中的查询所有这个超链接时,就能查询到上图右半部分的数据。
对于上述的功能,点击查询所有超链接是需要先请求后端的Servlet
,由Servlet
跳转到对应的页面进行数据的动态展示。而整个流程如下图:
- 编写BrandMapper
在mapper
包下创建BrandMapper
接口,在接口中定义selectAll()
方法
package com.itheima.mapper;
import com.itheima.pojo.Brand;
import java.util.List;
public interface BrandMapper {
/**
* 查询所有品牌数据
* @return
*/
List<Brand> selectAll();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.BrandMapper">
<resultMap id="BrandMap" type="Brand">
<id column="id" property="id" />
<result column="brand_name" property="brandName" />
<result column="company_name" property="companyName" />
</resultMap>
<sql id="brand_columns">
id, brand_name, company_name, ordered, description, status
</sql>
<select id="selectAll" resultMap="BrandMap">
select
<include refid="brand_columns" />
from tb_brand
</select>
</mapper>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 编写工具类
在com.itheima
包下创建util
包,并在该包下创建名为MyBatisUtil
的工具类
package com.itheima.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisUtil {
private static SqlSessionFactory factory;
static {
// 静态代码块会随着类的加载而自动执行,且只执行一次
try {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory() {
return factory;
}
}
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
- 编写
BrandService
在service
包下创建BrandService
类
package com.itheima.service;
import com.itheima.mapper.BrandMapper;
import com.itheima.pojo.Brand;
import com.itheima.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;
public class BrandService {
SqlSessionFactory factory = MyBatisUtil.getSqlSessionFactory();
/**
* 查询所有品牌数据
* @return
*/
public List<Brand> selectAll() {
// 调用BrandMapper.selectAll();
// 1. 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 2. 获取BrandMapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 3. 调用方法
List<Brand> brands = brandMapper.selectAll();
// 4. 释放资源
sqlSession.close();
// 5. 返回结果
return brands;
}
}
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
- 编写Servlet
在web
包下创建名为SelectAllServlet
的servlet
,该servlet
的逻辑如下:
- 调用
BrandService
的selectAll()
方法进行业务逻辑处理,并接收返回的结果 - 将上一步返回的结果存储到
request
域对象中 - 跳转到
brand.jsp
页面进行数据的展示
具体的代码实现:
package com.itheima.web;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 调用BrandService完成查询
List<Brand> brands = service.selectAll();
// 2. 存入request域中
request.setAttribute("brands", brands);
// 3. 转发到brand.jsp
request.getRequestDispatcher("/brand.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
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
- 编辑brand.jsp页面
将资料下的brand.html
页面拷贝到项目的webapp
目录下,并将该页面修改为brand.jsp
页面,在brand.jsp
页面中使用JSTL
和EL
表达式从request
域对象中获取名为brands
的集合数据并展示出来。页面内容如下:
- 编辑index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<a href="selectAllServlet">查询所有</a>
</body>
</html>
2
3
4
5
6
7
8
9
- 测试
启动服务器,在浏览器输入http://localhost/course/index.jsp,看到如下查询所有超链接,点击该连接就可以查询出所有的品牌数据
# 添加品牌
上图是添加功能流程,点击新增按钮后,会先跳转到addBrand.jsp
页面,在该页面输入要添加的数据,输入完成后点击提交按钮,需要将数据提交到后端,后端进行数据添加操作,并重新将所有品牌数据查询出来,整个流程如下:
接下来我们根据流程来实现添加品牌功能:
- 编写BrandMapper方法
在BrandMapper.java
接口和BrandMapper.xml
映射文件中分别定义add(Brand brand)
方法和add
对应的Statement
/**
* 添加品牌
* @param brand
*/
void add(Brand brand);
2
3
4
5
<insert id="add" parameterType="Brand">
insert into tb_brand(brand_name, company_name, ordered, description, status)
values(#{brandName}, #{companyName}, #{ordered}, #{description}, #{status})
</insert>
2
3
4
- 编写BrandService方法
在BrandService
类中定义添加品牌数据方法add(Brand brand)
/**
* 添加品牌
* @param brand
*/
public void add(Brand brand) {
// 1. 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 2. 获取BrandMapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 3. 调用方法
brandMapper.add(brand);
// 4. 提交事务
sqlSession.commit();
// 5. 释放资源
sqlSession.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 改进brand.jsp页面
在brand.jsp
表格的上面完善新增按钮的功能,给该按钮绑定单机事件,当点击了新增按钮需要跳转到addBrand.jsp
添加品牌数据页面
<input id="add" type="button" value="新增"><br>
<script>
document.getElementById("add").onclick = function() {
location.href = "addBrand.jsp";
}
</script>
2
3
4
5
注意
该script
标签建议放在body
结束标签的前面,注意是结束标签</body>
- 编写addBrand.jsp页面
从课程资料中将addBrand.html
页面拷贝到项目的webapp
下,并改成addBrand.jsp
动态页面
<%@ page contentType="text/html;charset=utf-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加品牌</title>
</head>
<body>
<h3>添加品牌</h3>
<form action="addServlet" method="post">
品牌名称:<input name="brandName"><br>
企业名称:<input name="companyName"><br>
排序:<input name="ordered"><br>
描述信息:<textarea rows="5" cols="20" name="description"></textarea><br>
状态:
<input type="radio" name="status" value="0">禁用
<input type="radio" name="status" value="1">启用<br>
<input type="submit" value="提交">
</form>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 编写AddServlet
在web
包下创建AddServlet
,该AddServlet
的业务逻辑如下:
- 设置处理
post
请求字符集 - 接收客户端提交的数据
- 将接收到的数据封装到
Brand
对象中 - 调用
BrandService
的add()
方法进行添加品牌的业务逻辑处理 - 跳转到
selectAllServlet
资源重新查询数据
代码如下:
package com.itheima.web;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 设置请求编码格式
request.setCharacterEncoding("utf-8");
// 2. 接收表单提交的数据,封装为一个Brand对象
String brandName = request.getParameter("brandName");
String companyName = request.getParameter("companyName");
String ordered = request.getParameter("ordered");
String description = request.getParameter("description");
String status = request.getParameter("status");
// 封装为Brand对象
Brand brand = new Brand();
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(Integer.parseInt(ordered));
brand.setDescription(description);
brand.setStatus(Integer.parseInt(status));
// 3. 调用service中的方法完成添加
service.add(brand);
// 4. 转发到查询所有品牌数据的Servlet
request.getRequestDispatcher("/selectAllServlet").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
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
- 测试
点击brand.jsp
页面的新增按钮,会跳转到addBrand.jsp
页面
点击提交按钮,就能看到如下页面,里面就包含我们刚刚添加的数据
# 修改品牌
如上图,点击每条数据后面的编辑按钮会跳转到修改页面,如下图:
在该修改页面我们可以看到将编辑按钮所在行的数据回显到表单,然后需要修改哪个数据就在表单中进行修改,然后点击提交按钮将数据提交到后端,后端在讲数据存储到数据库中。
从上面的示例中我们可以知道,修改功能要从两个方面进行实现,数据回显和修改操作。
- 回显数据
上图就是回显数据的效果,要实现这个效果,那当点击修改按钮时不能直接跳转到update.jsp
页面,而是需要先带着当前行数据的id
请求后端Servlet
,后端程序根据id
查询数据,将数据存储到域对象中跳转到update.jsp
页面进行数据展示,整体流程如下:
- 编写BrandMapper
在BrandMapper.java
接口和BrandMapper.xml
映射文件中分别定义方法selectById(int id)
和Statement
/**
* 根据id查询
* @param id
* @return
*/
Brand selectById(int id);
2
3
4
5
6
<select id="selectById" resultMap="BrandMap" parameterType="int">
select
<include refid="brand_columns" />
from tb_brand
where id = #{id}
</select>
2
3
4
5
6
- 编写BrandService方法
在BrandService
类中定义根据id
查询数据方法selectById(int id)
/**
* 根据id查询
* @param id
* @return
*/
public Brand selectById(int id) {
// 1. 获取sqlSession
SqlSession sqlSession = factory.openSession();
// 2. 获取BrandMapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 3. 调用方法
Brand brand = brandMapper.selectById(id);
// 4. 释放资源
sqlSession.close();
// 5. 返回查询结果
return brand;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 编写Servlet
在web
包下创建SelectByIdServlet
,该SelectByIdServlet
的逻辑如下:
- 获取请求数据
id
- 调用
BrandService
的selectById(int id)
方法进行数据查询 - 将查询到的数据存储到
request
域对象中 - 跳转到
update.jsp
页面进行数据展示
具体代码如下:
package com.itheima.web;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/selectByIdServlet")
public class SelectByIdServlet extends HttpServlet {
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 接收id
String id = request.getParameter("id");
// 2. 调用service查询方法
Brand brand = service.selectById(Integer.parseInt(id));
// 3. 存储到request域中
request.setAttribute("brand", brand);
// 4. 转发请求到update.jsp
request.getRequestDispatcher("/update.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
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
- 编写update.jsp页面
拷贝addBrand.jsp
页面,改名为update.jsp
并做出以下修改:
title
标签内容修改为修改品牌
form
标签的action
属性值修改为updateServlet
input
标签要进行数据回显,需要设置value
属性
品牌名称:<input name="brandName" value="${brand.brandName}"><br>
企业名称:<input name="companyName" value="${brand.companyName}"><br>
排序:<input name="ordered" value="${brand.ordered}"><br>
2
3
textarea
标签要进行数据回显,需要在标签体中使用EL表达式
描述信息:<textarea rows="5" cols="20" name="description">${brand.description} </textarea><br>
- 单选框使用
if
标签需要判断brand.status
的值是1
还是0
在指定的单选框上使用checked
属性,表示被选中状态
状态:
<c:if test="${brand.status == 0}">
<input type="radio" name="status" value="0" checked>禁用
<input type="radio" name="status" value="1">启用<br>
</c:if>
<c:if test="${brand.status == 1}">
<input type="radio" name="status" value="0" >禁用
<input type="radio" name="status" value="1" checked>启用<br>
</c:if>
2
3
4
5
6
7
8
9
10
综上,update.jsp
代码如下:
<%@ page contentType="text/html;charset=utf-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>修改品牌</title>
</head>
<body>
<h3>修改品牌</h3>
<form action="updateServlet" method="post">
品牌名称:<input name="brandName" value="${brand.brandName}"><br>
企业名称:<input name="companyName" value="${brand.companyName}"><br>
排序:<input name="ordered" value="${brand.ordered}"><br>
描述信息:<textarea rows="5" cols="20" name="description">${brand.description}</textarea><br>
状态:
<c:if test="${brand.status == 0}">
<input type="radio" name="status" value="0" checked />禁用
<input type="radio" name="status" value="1" />启用
</c:if>
<c:if test="${brand.status == 1}">
<input type="radio" name="status" value="0" />禁用
<input type="radio" name="status" value="1" checked />启用
</c:if>
<input type="submit" value="提交">
</form>
</body>
</html>
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
- 测试
启动服务器,访问http://localhost/course/index.jsp,效果如下:
- 修改数据
昨晚回显数据后,接下来我们就可以做修改数据了,而下图就是修改数据的效果:
在修改页面进行数据的修改,点击提交按钮,会将数据提交到后端程序,后端程序会对表中的数据进行修改操作,然后重新进行数据的查询操作,流程如下:
- 编写BrandMapper
在BrandMapper.java
接口和BrandMapper.xml
映射文件中分别定义修改方法update(Brand brand)
和修改Statement
/**
* 修改品牌数据
* @param brand
*/
void update(Brand brand);
2
3
4
5
<update id="update" parameterType="Brand">
update tb_brand
set brand_name = #{brandName},
company_name = #{companyName},
ordered = #{ordered},
description = #{description},
status = #{status}
where id = #{id}
</update>
2
3
4
5
6
7
8
9
- 编写BrandService方法
/**
* 修改品牌
* @param brand
*/
public void update(Brand brand) {
// 1. 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 2. 获取BrandMapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 3. 调用方法
brandMapper.update(brand);
// 4. 提交事务
sqlSession.commit();
// 5. 释放资源
sqlSession.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 编写UpdateServlet
在web
包下创建UpdateServlet
,该UpdateServlet
的逻辑如下:
- 设置请求字符集
- 接收客户端提交的数据
- 将接收到的数据封装到
Brand
对象中 - 调用
BrandService
的update()
方法进行修改的业务逻辑处理 - 跳转到
selectAllServlet
资源重新查询所有品牌数据
代码实现:
package com.itheima.web;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/updateServlet")
public class UpdateServlet extends HttpServlet {
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 设置请求字符集
request.setCharacterEncoding("utf-8");
// 2. 接收表单数据,封装为Brand对象
String id = request.getParameter("id");
String brandName = request.getParameter("brandName");
String companyName = request.getParameter("companyName");
String ordered = request.getParameter("ordered");
String description = request.getParameter("description");
String status = request.getParameter("status");
// 封装Brand对象
Brand brand = new Brand();
brand.setId(Integer.parseInt(id));
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(Integer.parseInt(ordered));
brand.setDescription(description);
brand.setStatus(Integer.parseInt(status));
// 3. 调用service的修改方法
service.update(brand);
// 4. 转发请求到selectAllServlet
request.getRequestDispatcher("/selectAllServlet").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
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
存在问题
update.jsp
页面提交数据时没有携带主键id
数据,而后台修改数据需要根据主键进行修改。
针对这个问题,一方面我们不希望在页面上讲主键id
展示给用户看,但是又希望在提交数据时能将主键id
提交到后端,此时我们可以在页面使用HTML
的隐藏域,在update.jsp
页面的表单中添加如下代码:
<%-- 隐藏域,提交id --%>
<input type="hidden" name="id" value="${brand.id}" />
2
update.jsp
页面的最终代码如下:
<%@ page contentType="text/html;charset=utf-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>修改品牌</title>
</head>
<body>
<h3>修改品牌</h3>
<form action="updateServlet" method="post">
<input name="id" value="${brand.id}" type="hidden" />
品牌名称:<input name="brandName" value="${brand.brandName}"><br>
企业名称:<input name="companyName" value="${brand.companyName}"><br>
排序:<input name="ordered" value="${brand.ordered}"><br>
描述信息:<textarea rows="5" cols="20" name="description">${brand.description}</textarea><br>
状态:
<c:if test="${brand.status == 0}">
<input type="radio" name="status" value="0" checked />禁用
<input type="radio" name="status" value="1" />启用
</c:if>
<c:if test="${brand.status == 1}">
<input type="radio" name="status" value="0" />禁用
<input type="radio" name="status" value="1" checked />启用
</c:if>
<input type="submit" value="提交">
</form>
</body>
</html>
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
- 测试
重启服务器,访问http://localhost/course/index.jsp,效果如下: