目录
1、jsp简述
2、JSP快速入门
2.1、搭建环境
2.2、导入JSP页面
2.3、编写代码
2.4、启动测试
3、JSP原理
4、JSP脚本
4.1、JSP脚本的分类
4.2、案例
4.2.1、需求
4.2.2、实现
编辑
4.2.3、测试
编辑4.3、JSP缺点
5、JSP语法
5.1、JSP页面的基本结构
5.2、声明变量和定义方法
5.3、Java程序片
5.4、Java表达式
5.5、JSP中的注释
5.6、JSP指令标记
5.6.1、page指令标记
5.6.2、include指令标记
5.7、JSP动作标记
5.7.1、include动作标记
5.7.2、param动作标记
5.7.4、useBean 动作标记
7、EL表达式
7.1、概述
7.2、代码演示
7.3、域对象
8、JSTL标签
8.1、概述
8.2、JSTL标签的使用
8.3、if标签
8.4、forEach标签
8.4.1、用法一:
8.4.2、用法二:
9、MVC和三层架构
9.1、MVC模式
9.2、三层架构
10、案例
10.1、环境准备
10.2、查询所有
10.2.1、编写BrandMapper接口
10.2.2、编写获取数据库连接的工具类
10.2.3、编写BrandService
10.2.4、编写Servlet
10.2.5、编写brand.jsp
10.2.6、测试
10.3、添加
10.3.1、编写BrandMapper接口方法
10.3.2、编写BrandService
10.3.3、改进brand.jsp页面
10.3.4、编写addBrand.jsp页面
10.3.5、编写Servlet
10.3.6、测试
10.4、修改
10.4.1、回显数据
10.4.2、编写BrandMapper接口方法
10.4.3、编写BrandService方法
10.4.4、编写Servlet
10.4.5、编写update.jsp页面
10.4.6、修改数据
10.4.7、编写BrandMapper接口方法
10.4.8、编写BrandService方法
10.4.9、编写Servlet
10.4.10、测试
10.5、删除
10.5.1、编写BrandMapper接口方法
10.5.4、测试
1、jsp简述
JSP是Java Server Page(Java服务端页面)的缩写,是由Sun公司倡导,许多公司参与,于1999年推出的一种Web服务设计标准。JSP是基于Java Servlet以及整个Java体系的Web开发技术,利用这一技术可以建立安全、跨平台、的先进动态网站。JSP以Java语言为基础,具有动态页面与静态页面分离、能够脱离平台的束缚以及编译后运行等优点,已经成为开发动态网站的主流技术之一。
JSP是一种动态网页技术,即可以定义HTML、JS、CSS等静态内容,还可以定义Java代码的动态内容,也就是JSP = HTML + Java
下面就是一个简单的jsp代码示例
<%@ 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>
上面代码 h1
标签内容是展示在页面上,而 Java 的输出语句是输出在 idea 的控制台。
那么,JSP 能做什么呢?现在我们只用 servlet
实现功能,看存在什么问题。如下图所示,当我们登陆成功后,需要在页面上展示用户名
上图的用户名是动态展示,也就是谁登陆就展示谁的用户名。只用 servlet
如何实现呢?
上面的代码有大量使用到 writer
对象向页面写标签内容,这样我们的代码就显得很麻烦;将来如果展示的效果出现了问题,排错也显得有点力不从心。而 JSP 是如何解决这个问题的呢?
如下图
上面代码可以看到里面基本都是 HTML
标签,而动态数据使用 Java 代码进行展示;这样操作看起来要比用 servlet
实现要舒服很多。
JSP 作用:简化开发,避免了在Servlet中直接输出HTML标签。
2、JSP快速入门
下面做一个简单的快速入门演示
2.1、搭建环境
创建一个Maven的web项目,项目结构如下
在pom.xml导入相关坐标依赖
<dependencies>
<!--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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>
注意:
该jsp依赖和servlet依赖的 scope
必须设置为 provided
,因为 tomcat 中有这个jar包了,所以在打包时我们是不希望将该依赖打进到我们工程的war包中。
2.2、导入JSP页面
在webapp目录下创建jsp页面
2.3、编写代码
<%@ 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.4、启动测试
结果如下,在浏览器页面中显示了 hello,jsp,在idea控制台出现了hello,jsp~
3、JSP原理
我们之前说JSP就是一个页面,那么在JSP中写html标签,我们能理解,但是为什么还可以书写Java代码呢?
因为JSP本质上就是一个Servlet。接下来了解一下访问jsp时的流程
1、浏览器第一次访问hello.jsp页面
2、tomcat服务器会将hello.jsp转换为名为 hello_jsp.java 的一个Servlet(Java文件)
3、tomcat再将转换的servlet编译成字节码文件 hello_jsp.class
4、tomcat会执行该字节码文件,向外提供服务
我们可以在项目所在磁盘目录下找到 \target\tomcat\work\Tomcat\localhost\jsp-demo\org\apache\jsp目录,在中国目录下可以看到转换后的Servlet
打开 hello_jsp.java 文件,查看其源代码
由上面的类的继承关系可知他继承自HttpJspBase类
查看tomcat源码,apache-tomcat-8.5.68-src\java\org\apache\jasper\runtime,该目录下就有HttpJspBase类
查看该类的继承关系
可以看到该类继承自 HttpServlet;那么hello_jsp.java 就间接继承了HttpServlet,由此也说明了hello_jsp.java是一个Servlet。
接着阅读 hello_jsp.java 源码,可以看到有一个名为 _jspService()
的方法,该方法就是每次访问 jsp
时自动执行的方法,和 servlet
中的 service
方法一样 。
而在 _jspService()
方法中可以看到往浏览器写标签的代码:
以前我们自己写Servlet是,这部分是由我们自己来写,现在学习了JSP以后,我们只需要书写JSP,由tomcat服务器完成这部分功能的即可
4、JSP脚本
JSP脚本用于在JSP页面中定义Java代码。在前面的入门案例中JSP页面中定义的Java代码就是JSP脚本。
4.1、JSP脚本的分类
JSP脚本有如下三个分类:
<%...%>:内容会直接放到_jspService()方法之中
<%=…%>:内容会放到out.print()中,作为out.print()的参数
<%!…%>:内容会放到_jspService()方法之外,被类直接包含
代码演示
在hello.jsp中书写Java程序片
<%
System.out.println("hello,jsp~");
int i = 3;
%>
通过浏览器访问 hello.jsp
后,查看转换的 hello_jsp.java
文件,i 变量定义在了 _jspService()
方法中
在hello.jsp中书写Java表达式
<%="hello"%>
<%=i%>
通过浏览器访问 hello.jsp
后,查看转换的 hello_jsp.java
文件,该脚本的内容被放在了 out.print()
中,作为参数
在hello.jsp中书写
<%!
void show(){
}
String name = "zhangsan";
%>
通过浏览器访问 hello.jsp
后,查看转换的 hello_jsp.java
文件,该脚本的内容被放在了成员位置
4.2、案例
4.2.1、需求
使用JSP脚本展示品牌数据
4.2.2、实现
1、导入brand.html静态页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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、创建brand.jsp,将brand.html内容拷贝过来
本案例本应该是与数据库交互,从数据库获取数据,封装至对象中,再通过jsp页面展示,但是为了简便,采取的数据是模拟的(假数据)
在brand.jsp中准备假数据
<%
// 查询数据库
List<Brand> brands = new ArrayList<Brand>();
brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));
brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0));
brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1));
%>
注意:这里的类是需要导包的,如下所示
3、修改刚刚从brand.html复制过来的html,使其成为动态的,如下所示
<%@ page import="com.clear.pojo.Brand" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<%
// 查询数据库
List<Brand> brands = new ArrayList<Brand>();
brands.add(new Brand(1, "三只松鼠", "三只松鼠", 100, "三只松鼠,好吃不上火", 1));
brands.add(new Brand(2, "优衣库", "优衣库", 200, "优衣库,服适人生", 0));
brands.add(new Brand(3, "小米", "小米科技有限公司", 1000, "为发烧而生", 1));
%>
<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>
<%
for (int i = 0; i < brands.size(); i++) {
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>
其中细节
4.2.3、测试
在浏览器地址栏输入localhost:8080/jsp-demo/brand.jsp
4.3、JSP缺点
通过上述案例中,我们可以看到JSP的很多去缺点
由于JSP页面内,既可以定义HTML标签,又可以定义Java代码,造成了以下问题:
1、书写麻烦。特别是复制的页面
既要书写HTML标签,还要写Java代码(可以通过后续学习MVC模式尽量避免)
2、阅读麻烦
上面案例的代码,相信你后期再看这段代码时还需要花费很长的时间去梳理
并且将来开发时,前端人员不会Java,看不懂
3、复杂度高:运行需要依赖于各种环境,JRE,JSP容器,JavaEE…
4、占内存和磁盘:JSP会自动生成.java和.class文件占磁盘,运行的是.class文件占内存
5、调试困难:出错后,需要找到自动生成的.java文件进行调试
6、不利于团队协作:前端人员不会 Java,后端人员不精 HTML
如果页面布局发生变化,前端工程师对静态页面进行修改,然后再交给后端工程师,由后端工程师再将该页面改为 JSP 页面
7、.....
由于上述的问题,JSP 已逐渐退出历史舞台,以后开发更多的是使用 HTML + Ajax来替代。Ajax 是我们后续会重点学习的技术。有个这个技术后,前端工程师负责前端页面开发,而后端工程师只负责前端代码开发。下来对技术的发展进行简单的说明
1、 第一阶段:使用 servlet
即实现逻辑代码编写,也对页面进行拼接。这种模式我们之前也接触过
2、第二阶段:随着技术的发展,出现了 JSP
,人们发现 JSP
使用起来比 Servlet
方便很多,但是还是要在 JSP
中嵌套 Java
代码,也不利于后期的维护
3、第三阶段:使用 Servlet
进行逻辑代码开发,而使用 JSP
进行数据展示
注意:不要直接在jsp书写java代码并不意味着不在jsp中书写java代码
4、第四阶段:使用 servlet
进行后端逻辑代码开发,而使用 HTML
进行数据展示。而这里面就存在问题,HTML
是静态页面,怎么进行动态数据展示呢?这就是 ajax
的作用了。
那既然 JSP 已经逐渐的退出历史舞台,那我们为什么还要学习 JSP
呢?原因有两点:
一些公司可能有些老项目还在用 JSP
,所以要求我们必须懂JSP
我们如果不经历这些复杂的过程,就不能体现后面阶段开发的简单
后续我们将学习使用EL表达式和JSTL标签库替代JSP中的Java代码
5、JSP语法
5.1、JSP页面的基本结构
JSP页面由五种元素组合而成:
普通的HTML标记和JavaScript标记
JSP标记,如指令标记、动作标记
变量和方法的声明
Java程序片
Java表达式
当Tomcat服务器上的一个JSP页面被第一次请求执行时,Tomcat服务器首先将JSP页面文件转译成一个Java文件,再将这个Java文件编译成字节码文件,然后通过执行这个字节码文件响应用户的请求。
当多个用户请求一个JSP页面时,Tomcat服务器为每个用户启动一个线程,该线程负责执行常驻内存的字节码文件来响应相应用户的需求。这些线程由Tomcat服务器来管理,将CPU的使用权在各个线程之间快速切换,以保证每个线程都有机会执行字节码文件。
字节码文件的任务就是:
把jsp页面中普通的html标记和JavaScript标记交给用户端浏览器执行显示。
jsp标记、方法的定义、Java程序片由服务器负责处理和执行,将需要显示的结果发送给用户端浏览器
Java表达式由服务器负责计算,并将结果转化为字符串,然后交给用户端浏览器负责显示
5.2、声明变量和定义方法
在<%!......%>标记符号之间声明变量、定义方法、类。
使用位置:
习惯放置于JSP页面指令之后,<HTML>之前
也可以放在<HTML>与</HTML>之间
1、声明的变量作为类的成员变量,这些变量占有内存空间知道tomcat服务器关闭才释放。声明的变量在整个JSP页面内部有效
当多个用户请求一个JSP页面时,Tomcat服务器为每个用户启动一个线程,因此这些线程共享JSP页面中的成员变量
2、在方法中声明的变量只在方法中有效,方法被调用完毕后即可释放这些变量的内存
5.3、Java程序片
可以在<%......%>标记符号之间插入Java程序片。
一个JSP页面可以有许多程序片,这些程序片被tomcat服务器顺序执行。
在程序片中声明的变量称为局部变量。
局部变量在JSP页面后继的所有程序片以及表达式部分内部有效
使用位置:
Java程序片可以写在<HTML>之前
也可以放在<HTML>与</HTML>之间或</HTML>之后
5.4、Java表达式
可以在<%=......%>标记符号之间插入一个可求值的表达式。
表达式的值由服务器负责计算,并将计算结果用字符串形式发送到用户端浏览器显示。
注意:
在JSP页面中,表达式的值被表示成一个字符串的形式,即tomcat服务器将表达式的结果转变为字符串,然后发送给用户的浏览器。因此,在编写JSP页面时,要把Java表达式按普通的文本来使用
使用位置:
Java表达式可以写在<HTML>之前
也可以放在<HTML>与</HTML>之间或</HTML>之后
5.5、JSP中的注释
HTML注释
<!--注释内容-->
JSP注释
<%-- 注释内容--%>
Tomcat服务器将忽略掉注释,即在编译JSP页面时忽略掉JSP注释
CSS注释
/* 注释内容*/
5.6、JSP指令标记
5.6.1、page指令标记
page执行用来定义整个JSP页面的一些属性和这些属性的值,属性值用单引号或双引号括起来。
page指令标记使用方式有两种:
方式一:
<% @ page 属性1=“属性1的值”%>
<% @ page 属性2=”属性2的值“%>
...
<% @ page 属性n=“属性n的值”%>
方式二:
<% @ page 属性1=“属性1的值” 属性2=“属性2的值” ...%>
page指令的作用对整个JSP页面有效,与其书写的位置无关。习惯上把page指令写在JSP页面的最前面。
page指令标记有众多属性,contentType、import、language、session、buffer、autoFlush、isThreadSafe、pageEncoding、inform等
1、contentType属性
确定JSP页面响应的MIME类型
eg:
<% @ page contentType="text/html"%>
contentType的属性值有:text/html、text/plain、image/gif、image/x-xbitmap、image/jpeg、imag/pjpeg、application/x-shockwave-flash、application/vnd.ms-powerpoint、application/vnd.ms-excel、application/msword等
注意:
如果不使用page指令为contentType指定值,那么contentType默认值为"text/html"
不允许使用page指令给contentType属性指定两个不同的属性值
如下是错误的示范
<% @ page contentType="text/html"%>
<% @ page contentType="application/msword"%>
为contentType指定值的同时可以为其附加属性 charset指定一个值(默认为ISO-8859-1),
例如
<% @ page contentType="text/html;charset=gb2312"%>
2、pageEncoding属性
pageEncoding属性的默认值为UTF-8。
注意:和contentType的附加属性charset的值意义不同。pageEncoding属性值是定义JSP页面使用的编码,即是告诉tomcat服务器的解析器用什么样的编码解析JSP页面中的字符
eg:指定JSP页面编码为utf-8
<% @ page pageEncoding="utf-8"%>
注意:
不允许使用page指令给pageEncoding属性指定两个不同的属性值
3、language属性
language属性定义JSP页面使用的脚本语言,该属性的值目前只能取值为“Java”。
格式如下:
<% @ page language="java"%>
language属性的默认值是“Java”,即如果在JSP页面中没有使用page指令指定该属性的值,那么默认就有如下page指令
<% @ page language="java"%>
4、import属性
该属性的作用是在JSP页面中引入Java运行环境提供的包中的类,这样在JSP页面的程序片、变量、方法等部分即可使用包中的类。
可以为该属性指定多个值,该属性的值可以是某个包中的所有类或是某个具体的类
eg:
<% @ page import="java.io.*","java.time.LocalDate"%>
注意:
JSP页面默认import属性已经有如下的值:
“java.lang.*” "javax.servlet.*" "javax.servlet.jsp.*" "javax.servlet.http.*"
当为import指定多个属性值时,比如:
<% @ page import="java.util.*"%>
<% @ page import="java.io.*"%>
那么JSP引擎把JSP页面转译成的Java文件中会有如下的import语句
import java.util.*;
import java.io.*;
5、session属性
设置是否需要使用内置的session对象。session的属性值可以是true或false。session属性的默认属性值为true
6、buffer属性
内置输出流对象out负责将服务器的某些信息或运行结果发送到用户端显示。buffer属性用来指定out设置的缓冲区的大小或不使用缓冲区。
eg:
<% page buffer="24kb"%>
其中,buffer属性的默认值是8kb。buffer属性可以取值“none”,即设置out不使用缓冲区。
7、autoFlush属性
autoFlush属性可以指定out的缓冲区被填满时,缓冲区是否自动刷新。
autoFlush的属性值可以是true或false。autoFlush属性的默认属性值为true
8、isThreadSafe属性
用户设置访问JSP页面是否是线程安全的。
isThreadSafe的属性值可以是true或false。isThreadSafe属性的默认属性值为true
9、info属性
info属性的属性值是一个字符串,其目的是为JSP页面准备一个常用但可能要经常修改的字符串
<% @ page info="we are students"%>
可以在JSP页面中使用如下方法获取info属性的属性值:
getServletInfo();
5.6.2、include指令标记
如果需要在JSP页面内某处整体嵌入一个文件,就可以考虑使用include指令标记,语法格式如下:
<% @ include file="文件的URL"%>
注意:
该文件的编码必须和当前JSP页面一致
使用include指令可以实现代码的复用
5.7、JSP动作标记
动作标记是一种特殊的标记,它影响JSP运行时的功能。
5.7.1、include动作标记
include动作标记语法格式为:
<jsp:include page="文件的URL"/>
或者
<jsp:include page="文件的URL">
param子标记
</jsp:include>
注意:
当include动作标记不需要param子标记时,必须使用第一种形式。
include动作标记告诉JSP页面动态包含一个文件,即JSP页面运行时才将文件加入。
尽管include动作标记和include指令标记的作用都是处理所需的文件,但是处理方式和处理时间都是不同的。
include指令标记是在编译阶段就处理所需要的文件,被处理的文件在逻辑和语法上依赖于当前JSP页面,优点是页面的执行速度快;而include动作标记是在JSP页面运行时才处理文件,被处理的文件在逻辑和语法上独立于当前JSP页面,其优点是可以使用param子标记更灵活的处理所需文件,缺点是执行速度慢些
5.7.2、param动作标记
param标记以“名字-值”对的形式为其他标记提供附加信息,param标记不能独立使用,须作为jsp:include、jsp:forward标记的子标记来使用
param动作标记格式:
<jsp:param name="参数" value="参数的值"/>
include动作标记通过使用param子标记来处理加载的文件,比include指令标记更加灵活。
5.7.3、forward动作标记
forward动作标记的语法格式:
<jsp:forward page="要转向的页面"/>
或者
<jsp:forward page="要转向的页面">
param子标记
</jsp:forward>
forward动作标记的作用:从该指令处停止当前页面的执行,而转向执行page属性指定的JSP页面
注意:
当include动作标记不需要param子标记时,必须使用第一种形式。
当前页面使用forward动作标记转向后,尽管用户看到了转型后的页面的效果,但浏览器地址栏中显示的任然是转向前的JSP页面的URL地址(forward即浏览器地址栏不发生改变),因此,如果刷新浏览器的显示,将再次执行当前浏览器地址栏显示的JSP页面
5.7.4、useBean 动作标记
1、使用JSP动作标记useBean加载使bean,语法格式如下
<jsp:useBean id="bean的名字" class="创建的bean的类" scope="bean的有效范围"/>
或者
<jsp:useBean id="bean的名字" class="创建的bean的类" scope="bean的有效范围">
</jsp:useBean>
其中的“创建的bean的类”要带有包名,例如:
<jsp:useBean id="circle" class="tom.jiafei.Circle" scope="page"/>
2、bean的加载原理
7、EL表达式
7.1、概述
EL(全称Expression Language )表达式语言,用于简化 JSP 页面内的 Java 代码。
EL 表达式的主要作用是 获取数据。其实就是从域对象中获取数据,然后将数据展示在页面上。
而EL表达式的语法也比较简单,
${expression}
例如以下就是获取域中存储的key为brands的数据
${brands}
7.2、代码演示
定义Servlet,在Servlet中封装一些数据并存储到request域对象中并转发到el-demo.jsp页面
@WebServlet("/demo1")
public class ServletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 准备数据
List<Brand> brands = new ArrayList<Brand>();
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);
}
}
注意:这里必须使用转发,因为只有转发才可以共享request域对象中的数据
在el-demo.jsp中通过EL表达式获取数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
${brand}
</body>
</ht
测试,在浏览器输入 http://localhost:8080/jsp-demo/demo1
,页面效果如下:
7.3、域对象
JavaWeb中有四大域对象,分别是:
page:当前页面有效
request:当前请求有效
session:当前会话有效
application:当前应用有效
el表达式获取数据,会依次从着4个域中寻找,直到找到为止。这四大域对象作用范围如下:
例如: ${brands},el 表达式获取数据,会先从page域对象中获取数据,如果没有再到 requet 域对象中获取数据,如果再没有再到 session 域对象中获取,如果还没有才会到 application 中获取数据。
8、JSTL标签
8.1、概述
JSP标准标签库(Jsp Standarded Tag Library),使用标签取代JSP页面上的Java代码。如下代码就是JSTL标签
<c:if test="${flag == 1}">
男
</c:if>
<c:if test="${flag == 2}">
女
</c:if>
上面代码看起来是不是比JSP中嵌套Java代码看起来舒服多了。而且前端工程师对标签是特别敏感的,他们看到这段代码是能看懂的。
JSTL提供了很多标签,如下图:
我们只对两个最常用的标签进行讲解,<c:forEach>标签和 <c:if>
标签。
8.2、JSTL标签的使用
JSTL 使用也是比较简单的,分为如下步骤:
1、导入坐标
<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、在JSP页面上引入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3、使用标签
8.3、if标签
<c:if> 相当于if判断
属性 test,用于定义条件表达式
<c:if test="${flag == 1}">
男
</c:if>
<c:if test="${flag == 2}">
女
</c:if>
代码演示:
定义一个 servlet
,在该 servlet
中向 request 域对象中添加 键是 status
,值为 1
的数据
@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);
}
}
定义 jstl-if.jsp
页面,在该页面使用 <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>
注意:
在该页面一定要引入 JSTL核心标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
8.4、forEach标签
<c:forEach>
:相当于 for 循环。java中有增强for循环和普通for循环,JSTL 中的 <c:forEach>
也有两种用法
8.4.1、用法一:
类似于Java中的增强for循环。涉及到的 <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>
代码演示:
定义Servlet,在Servlet中封装一些数据并存储到request域对象中并转发到jstl-foreach.jsp页面
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 准备数据
List<Brand> brands = new ArrayList<Brand>();
brands.add(new Brand(1, "三只松鼠", "三只松鼠", 100, "三只松鼠,好吃不上火", 1));
brands.add(new Brand(2, "优衣库", "优衣库", 200, "优衣库,服适人生", 0));
brands.add(new Brand(3, "小米", "小米科技有限公司", 1000, "为发烧而生 ", 1));
//2.存储数据
request.setAttribute("brands",brands);
//3.转发到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);
}
}
定义 jstl-foreach.jsp
页面,在该页面使用 <c:forEach>
标签
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<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>${status.count}</td> <!--标准单元格-->
<td>${brand.brandName}</td>
<td>${brand.companyName}</td>
<td>${brand.ordered}</td>
<td>${brand.description}</td>
<c:if test="${brand.status == 1}">
<td>启用</td>
</c:if>
<c:if test="${brand.status != 1}">
<td>禁用</td>
</c:if>
<td><a href="#">修改</a> <a href="#">删除</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
效果如下
8.4.2、用法二:
类似于Java中的普通for循环。涉及到的 <c:forEach>
中的属性如下
begin:开始数
end:结束数
step:步长
实现代码如下:
<c:forEach begin="0" end="10" step="1" var="i">
${i}
</c:forEach>
9、MVC和三层架构
MVC 模式和三层架构是一些理论的知识,将来我们使用了它们进行代码开发会让我们代码维护性和扩展性更好。
9.1、MVC模式
MVC 是一种分层开发的模式,其中:
M:Model,业务模型,处理业务
V:View,视图,界面展示
C:Controller,控制器,处理请求,调用模型和视图
控制器(serlvlet)用来接收浏览器发送过来的请求,控制器调用模型(JavaBean)来获取数据,比如从数据库查询数据;控制器获取到数据后再交由视图(JSP)进行数据展示
MVC的好处:
职责单一,互不影响。每个角色做它自己的事情,各司其职。
有利于分工协作
有利于组件重用
9.2、三层架构
三层架构是将我们的项目分成了三个层面,分别是表现层、业务逻辑层、数据访问层
数据访问层:对数据库的CRUD基本操作
业务逻辑层:对业务逻辑进行封装,组合数据访问层层中基本功能,形成复杂的业务逻辑功能。例如 注册业务功能
,我们会先调用 数据访问层
的 selectByName()
方法判断该用户名是否存在,如果不存在再调用 数据访问层
的 insert()
方法进行数据的添加操作
表现层:请求数据,封装数据,调用业务逻辑层,响应数据
而整个流程是,浏览器发送请求,表现层的Servlet接收请求并调用业务逻辑层的方法进行业务逻辑处理,而业务逻辑层方法调用数据访问层方法进行数据的操作,依次返回到serlvet,然后servlet将数据交由 JSP 进行展示。
三层架构的每一层都有特有的包名称:
表现层: com.clear.controller
或者 com.clear.web
业务逻辑层:com.clear.service
数据访问层:com.clear.dao
或者 com.clear.mapper
后期我们还会学习一些框架,不同的框架是对不同层进行封装的
9.3、MVC和三层架构
通过 MVC 和 三层架构 的学习,有些人肯定混淆了。那他们有什么区别和联系?
如上图上半部分是 MVC 模式,上图下半部分是三层架构。 MVC 模式
中的 C(控制器)和 V(视图)就是 三层架构
中的表现层,而 MVC 模式
中的 M(模型)就是 三层架构
中的 业务逻辑层 和 数据访问层。
可以将 MVC 模式
理解成是一个大的概念,而 三层架构
是对 MVC 模式
实现架构的思想。 那么我们以后按照要求将不同层的代码写在不同的包下,每一层里功能职责做到单一,将来如果将表现层的技术换掉,而业务逻辑层和数据访问层的代码不需要发生变化。
10、案例
需求:完成品牌数据的增删改查
这个功能我们之前一直在做,而这个案例是将前面所学的所有的内容(包含 MVC模式 和 三层架构)进行应用,并将整个流程贯穿起来。
10.1、环境准备
1、创建新的模块brand-demo,补全项目结构
2、引入坐标
3、准备数据库表tb_brand
4、准备实体类Brand
5、Mybatis基础环境
Mybatis-config.xml
BrandMapper.xml
BrandMapper接口
1、创建新的模块brand-demo,补全项目结构
Project Structrue -> Moude -> 点击加号 -> New Module -> 选择Mvaen ->Next -> 为模块命名 -> Finish -> Apply -> OK
项目结构如下图所示
接下来要补全项目结构
第一步,现在pom.xml 添加一条
<packaging>war</packaging>
以表明这是一个web项目
第二步,补全项目结构
Project Structrue -> Facets -> 选择刚刚创建的模块
如下所示
第三步,继续补全项目结构,如下所示
2、引入坐标
引入坐标。我们只要分析出要用到哪儿些技术,那么需要哪儿些坐标也就明确了
需要操作数据库。mysql驱动包
要使用mybaits框架。mybatis的依赖包
web项目所需要的的Servlet和jsp。servlet和jsp的依赖
需要使用jstl进行数据展示。jstl的依赖包
还需导入tomcat的插件
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>org.example</groupId>
<artifactId>brand-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</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>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>
</project>
3、准备数据库表tb_brand
-- 删除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);
4、准备实体类Brand
package com.clear.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 +
'}';
}
}
5、Mybatis基础环境
Mybatis-config.xml
<?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.clear.pojo"/>
</typeAliases>
<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://localhost:3306/db1?useSSL=false&useServerPrepStmts=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
<package name="com.clear.mapper"/> <!--扫描mapper目录下所有接口-->
</mappers>
</configuration>
BrandMapper.xml
在与mapper接口放在在同一目录下创建SQL映射文件
在 resources
下创建放置映射配置文件的目录结构 com/clear/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.clear.mapper.BrandMapper">
</mapper>
BrandMapper接口
package com.clear.mapper;
public interface BrandMapper {
}
10.2、查询所有
当我们点击 index.html
页面中的 查询所有
这个超链接时,就能查询到上图右半部分的数据。
在webapp目录下,创建的index.html如下所示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/brand-demo/SelectAllServlet">查询所有</a>>
</body>
</html>
对于上述的功能,点击 查询所有
超链接是需要先请后端的 servlet
,由 servlet
跳转到对应的页面进行数据的动态展示。而整个流程如下图:
10.2.1、编写BrandMapper接口
在 mapper
包下创建创建 BrandMapper
接口,在接口中定义 selectAll()
方法
由于整个SQL比较简单,因此这里用注解方式书写SQL
/**
* 查询所有
*
* @return
*/
@Select("select * from tb_brand")
List<Brand> selectAll();
10.2.2、编写获取数据库连接的工具类
在 com.clear
包下创建 utils
包,并在该包下创建名为 SqlSessionFactoryUtils
工具类
/**
* 获取SelSessionFactory对象的工具类
*/
public class SqlSessionFactoryUtils {
/**
* 私有构造器
*/
private SqlSessionFactoryUtils() {
}
private static SqlSessionFactory sqlSessionFactory;
static {
//静态代码块会随着类的加载而自动执行,且只执行一次
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
}
10.2.3、编写BrandService
在 service
包下创建 BrandService
类
public class BrandService {
// 1、获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
/**
* 查询所有
*
* @return
* @throws Exception
*/
public List<Brand> selectAll() {
//2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 获取BrandMapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 调用方法
List<Brand> brands = brandMapper.selectAll();
sqlSession.close();
return brands;
}
}
10.2.4、编写Servlet
在 web
包下创建名为 SelectAllServlet
的 servlet
,该 servlet
的逻辑如下:
调用 BrandService
的 selectAll()
方法进行业务逻辑处理,并接收返回的结果
将上一步返回的结果存储到 request
域对象中
跳转到 brand.jsp
页面进行数据的展示
@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);
}
}
10.2.5、编写brand.jsp
将 下面的 brand.html
页面修改成 brand.jsp
页面,而 brand.jsp
页面在表格中使用 JSTL
和 EL表达式
从request域对象中获取名为 brands
的集合数据并展示出来。页面内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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>
修改后的brand.jsp页面如下
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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>${status.count}</td>
<td>${brand.brandName}</td>
<td>${brand.companyName}</td>
<td>${brand.ordered}</td>
<td>${brand.description}</td>
<c:if test="${brand.status == 1}">
<td>启用</td>
</c:if>
<c:if test="${brand.status != 1}">
<td>禁用</td>
</c:if>
<td>
<a href="#" >修改</a>
<a href="#">删除</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
10.2.6、测试
启动服务器测试,并在浏览器输入 http://localhost:8080/brand-demo/index.html
,看到如下 查询所有
的超链接,点击该链接就可以查询出所有的品牌数据
但是,我们发现 品牌名称和企业名称两列都是空的,为什么出现这个问题呢?是因为查询到的字段名和实体类对象的属性名没有一一对应。相比看到这大家一定会解决了,就是在映射配置文件中使用 resultMap
标签定义映射关系。映射配置文件内容如下:
并且在 BrandMapper
接口中的 selectAll()
上使用 @ResuleMap
注解指定使用该映射
重启服务器,再次访问就能看到我们想要的数据了
10.3、添加
上图是做 添加 功能流程。点击 新增
按钮后,会先跳转到 addBrand.jsp
新增页面,在该页面输入要添加的数据,输入完毕后点击 提交
按钮,需要将数据提交到后端,而后端进行数据添加操作,并重新将所有的数据查询出来。整个流程如下:
接下来我们根据流程来实现功能:
10.3.1、编写BrandMapper接口方法
在 BrandMapper
接口,在接口中定义 add(Brand brand)
方法
为了简化,这里依然采用注解形式
/**
* 添加商品
* @param brand
*/
@Insert("insert into tb_brand(brand_name,company_name,ordered,description,status)" +
" values(#{brandName},#{companyName},#{ordered},#{description},#{status})")
void add(Brand brand);
10.3.2、编写BrandService
在 BrandService
类中定义添加品牌数据方法 add(Brand brand)
/**
* 添加
* @param brand
*/
public void add(Brand brand){
// 获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(false);
// 获取Mapper
BrandMapper brandMapper= sqlSession.getMapper(BrandMapper.class);
try {
// 调用方法
brandMapper.add(brand);
// 提交事务
sqlSession.commit();
sqlSession.close();
} catch (Exception exception) {
sqlSession.rollback();
exception.printStackTrace();
}
}
10.3.3、改进brand.jsp页面
我们需要在该页面表格的上面添加 新增
按钮
并给该按钮绑定单击事件,当点击了该按钮需要跳转到 brand.jsp
添加品牌数据的页面
<script>
document.getElementById("add").onclick = function (){
location.href = "/brand-demo/addBrand.jsp";
}
</script>
注意:
该 script
标签建议放在 body
结束标签前面。
10.3.4、编写addBrand.jsp页面
将如下的 addBrand.html
页面修改成 addBrand.jsp
动态页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加品牌</title>
</head>
<body>
<h3>添加品牌</h3>
<form action="" 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>
修改成的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="/brand-demo/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>
10.3.5、编写Servlet
在 web
包下创建 AddServlet
的 servlet
,该 servlet
的逻辑如下:
设置处理post请求乱码的字符集
接收客户端提交的数据
将接收到的数据封装到 Brand
对象中
调用 BrandService
的add()
方法进行添加的业务逻辑处理
跳转到 selectAllServlet
资源重新查询数据
具体的代码如下:
@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//处理POST请求的乱码问题
request.setCharacterEncoding("utf-8");
//1. 接收表单提交的数据,封装为一个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));
//2. 调用service 完成添加
service.add(brand);
//3. 转发到查询所有Servlet
request.getRequestDispatcher("/selectAllServlet").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
10.3.6、测试
点击 brand.jsp
页面的 新增
按钮,会跳转到 addBrand.jsp
页面
点击 提交
按钮,就能看到如下页面,里面就包含我们刚添加的数据
10.4、修改
点击每条数据后面的 修改按钮会跳转到修改页面
在该修改页面我们可以看到将 修改 按钮所在行的数据 回显 到表单,然后需要修改那个数据在表单中进行修改,然后点击 提交
的按钮将数据提交到后端,后端再将数据存储到数据库中。
所以我们知道 修改
功能需要从两方面进行实现,数据回显和修改操作。
10.4.1、回显数据
上图就是回显数据的效果。要实现这个效果,那当点击 修改
按钮时不能直接跳转到 update.jsp
页面,而是需要先带着当前行数据的 id
请求后端程序,后端程序根据 id
查询数据,将数据存储到域对象中跳转到 update.jsp
页面进行数据展示。整体流程如下
10.4.2、编写BrandMapper接口方法
在 BrandMapper
接口,在接口中定义 selectById(int id)
方法
为了简便,这里依然采用注解
/**
* 根据id查询
* @param id
* @return
*/
@Select("select * from tb_brand where id=#{id}")
@ResultMap("brandResultMap")
Brand selectById(int id);
10.4.3、编写BrandService方法
在 BrandService
类中定义根据id查询数据方法 selectById(int id)
/**
* 根据id查询
* @param id
* @return
*/
public Brand selectById(int id){
//2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 获取BrandMapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 调用方法
Brand brand = brandMapper.selectById(id);
return brand;
}
10.4.4、编写Servlet
在 web
包下创建 SelectByIdServlet
的 servlet
,该 servlet
的逻辑如下:
获取请求数据 id
调用 BrandService
的 selectById()
方法进行数据查询的业务逻辑
将查询到的数据存储到 request 域对象中
跳转到 update.jsp
页面进行数据真实
@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);
}
}
10.4.5、编写update.jsp页面
拷贝 addBrand.jsp
页面,改名为 update.jsp
并做出以下修改:
title
标签内容改为 修改品牌
form
标签的 action
属性值改为 /brand-demo/updateServlet
input
标签要进行数据回显,需要设置 value
属性
textarea
标签要进行数据回显,需要在标签体中使用 EL表达式
单选框使用 if
标签需要判断 brand.status
的值是 1 还是 0 在指定的单选框上使用 checked
属性,表示被选中状态
修改后的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="/brand-demo/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">启用<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>
<input type="submit" value="提交">
</form>
</body>
</html>
10.4.6、修改数据
做完回显数据后,接下来我们要做修改数据了,而下图是修改数据的效果:
在修改页面进行数据修改,点击 提交
按钮,会将数据提交到后端程序,后端程序会对表中的数据进行修改操作,然后重新进行数据的查询操作。整体流程如下:
10.4.7、编写BrandMapper接口方法
在 BrandMapper
接口,在接口中定义 update(Brand brand)
方法
这个方法采用映射文件的方式
/**
* 修改
* @param brand
*/
void update(Brand brand);
下面是在SQL映射文件(BrandMapper.xml)编写SQL语句
<update id="update" >
update tb_brand
set brand_name=#{brandName},
company_name=#{companyName},
ordered=#{ordered},
description=#{description},
status=#{status}
where id=#{id}
</update>
10.4.8、编写BrandService方法
在 BrandService
类中定义根据id查询数据方法 update(Brand brand)
/**
* 修改
* @param brand
*/
public void update(Brand brand){
// 1、获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(false);
// 2、获取Mapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 3、调用方法
try{
brandMapper.update(brand);
sqlSession.commit();
sqlSession.close();
} catch(Exception e){
sqlSession.rollback();
e.printStackTrace();
}
}
10.4.9、编写Servlet
在 web
包下创建 AddServlet
的 servlet
,该 servlet
的逻辑如下:
设置处理post请求乱码的字符集
接收客户端提交的数据
将接收到的数据封装到 Brand
对象中
调用 BrandService
的update()
方法进行添加的业务逻辑处理
跳转到 selectAllServlet
资源重新查询数据
具体的代码如下:
@WebServlet("/updateServlet")
public class UpdateServlet extends HttpServlet {
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//处理POST请求的乱码问题
request.setCharacterEncoding("utf-8");
//1. 接收表单提交的数据,封装为一个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));
//2. 调用service 完成修改
service.update(brand);
//3. 转发到查询所有Servlet
request.getRequestDispatcher("/selectAllServlet").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
注意:这里要去修改brand.jsp中的 <a>标签的href,如下图所示
存在问题:update.jsp 页面提交数据时是没有携带主键数据的,而后台修改数据需要根据主键进行修改。
针对这个问题,我们不希望页面将主键id展示给用户看,但是又希望在提交数据时能将主键id提交到后端。此时我们就想到了在学习 HTML 时学习的隐藏域,在 update.jsp
页面的表单中添加如下代码:
修改后的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="/brand-demo/updateServlet" method="post">
<%--隐藏域,提交id--%>
<input type="hidden" name="id" value="${brand.id}">
品牌名称:<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">启用<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>
<input type="submit" value="提交">
</form>
</body>
</html>
接着还需要修改UpdateSetvlt,修改如下
10.4.10、测试
测试回显,点击需要修改的品牌
成功回显数据,如下所示
修改数据用户,如下所示,成功修改
10.5、删除
10.5.1、编写BrandMapper接口方法
为了简便,这里依然采用注解
/**
* 根据id删除
* @param id
*/
@Delete("delete from tb_band where id=#{id}")
void delete(int id);
10.5.2、编写BrandService方法
/**
* 根据id删除
* @param id
*/
public void delete(int id) {
// 1、获取SQlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(false);
// 2、获取Mapper
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// 3、调用方法
try {
brandMapper.delete(id);
sqlSession.commit();
sqlSession.close();
} catch (Exception e) {
e.printStackTrace();
}
}
10.5.3、编写Servlet
@WebServlet("/deleteServlet")
public class DeleteServlet extends HttpServlet {
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 接收id
int id = Integer.parseInt(request.getParameter("id"));
// 调用方法,完成删除
service.delete(id);
//3. 转发到查询所有Servlet
request.getRequestDispatcher("/selectAllServlet").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
修改brand.jsp中的 <a>标签的href,如下图所示
10.5.4、测试
选择要删除的项
如图所示,删除成功