html:静态网页,内容写完了之后,就固定下来了,不会发生改变。
Java server page(java服务器页面),动态网页!JSP=java+html JSP本质就是Servlet
它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术。
需求: 我们要向页面动态输出一个表格. 发现特别的繁琐
servlet在展示页面的时候,相当的繁琐。sun公司为了解决这个问题,参照asp开发了一套动态网页技术jsp。
jsp就是简化书写!
JSP会翻译(通过默认的JspServlet,JSP引擎)成Servlet(.java),Servlet编译成class文件
JSP执行流程
1. 客户端发起第一次请求xxx.jsp,服务器就会找到对应的jsp文件
2. 服务器会将jsp文件翻译成xxx_jsp.java
3. 将xxx_jsp.java编译成xxx_jsp.class
4. 服务器执行xxx_jsp.class文件 输出结果给客户端浏览器
JSP:是一个动态网页,在jsp中既可以写java代码,又可以写html代码,作用:简化开发
JSP本质就是一个Servlet
JSP执行流程:请求–>index.jsp-翻译->index_jsp.java-编译->index_jsp.class–>执行–>响应给浏览器
在目前实际开发中,jsp基本不再使用了,1.执行效率低下 2.不利于分工协作
我们可以通过JSP脚本在JSP页面上编写Java代码. 一共有三种方式:
类型 | 翻译成Servlet对应的部分 | 注意 |
---|---|---|
<%…%>:Java程序片段 | 翻译成Service()方法里面的内容, 局部的 | |
<%=…%>:输出表达式 | 翻译成Service()方法里面的内容,相当于调用out.print() | 输出表达式不能以;结尾 |
<%!..%>:声明成员变量 | 翻译成Servlet类里面的内容 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
<%!
//声明成员变量或方法 会被翻译到Servlet类中
String hehe = "hehe SZ118";
%>
<%
//编写java代码
System.out.println("Hello world!");
//声明一个变量 局部变量 会被翻译到service方法中
String msg = "Hello";
%>
Hello World
<%--输出表达式:用于输出数据到页面--%>
<%=msg %>
<%=hehe %>
注释类型 |
---|
HTML注释 |
JAVA注释 // 、/* */ |
JSP注释: <%–注释内容–%> |
JSP注释和java脚本中的java注释内容不会展现在网页源码中,而html注释会展现在网页源码中。
注释快捷键:Ctrl+Shift+/
/**
* 登录实现步骤:
* 0.处理请求响应中文乱码
* 1.获取请求参数【用户名和密码】
* 2.根据用户名和密码使用MyBatis查询数据库tb_user表 返回user对象
* 3.判断user对象是否为null
* 3.1:user==null:登录失败
* 3.2:user!=null:登录成功
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
SqlSession sqlSession = null;
try {
//* 0.处理请求响应中文乱码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//* 1.获取请求参数【用户名和密码】
Map<String, String[]> parameterMap = request.getParameterMap();
User user = new User();
BeanUtils.populate(user,parameterMap);
//* 2.根据用户名和密码使用MyBatis查询数据库tb_user表 返回user对象
//2.1:加载MyBatis配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.2:获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//2.3:获取SqlSession对象
sqlSession = sqlSessionFactory.openSession();
//2.4:获取dao接口代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
//2.5:调用方法
User loginUser = userDao.select(user);
//* 3.判断loginUser对象是否为null
if(loginUser==null){
//* 3.1:loginUser==null:登录失败
response.getWriter().print("登录失败!");
}else{
//* 3.2:loginUser!=null:登录成功
response.getWriter().print("登录成功!");
//1.登录成功后 判断用户是否勾选了记住用户名复选框
//优化:如果没有勾选记住用户名复选框 则remember参数的值为null
String[] remember = parameterMap.get("remember");
if(remember!=null && remember[0].equals("on")){
//2.1勾选了:将用户名和密码存入Cookie写给客户端浏览器, 并设置有效时间5天
Cookie usernameCookie = new Cookie("username", loginUser.getUsername());
Cookie passwordCookie = new Cookie("password", loginUser.getPassword());
usernameCookie.setMaxAge(60*60*24*5);
passwordCookie.setMaxAge(60*60*24*5);
response.addCookie(usernameCookie);
response.addCookie(passwordCookie);
}
//2.2:没有勾选:不管它|删除Cookie
}
} catch (Exception e) {
e.printStackTrace();
response.getWriter().print("服务器异常!");
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
<%@ page import="com.itheima.utils.CookieUtils" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
<%--
客户端浏览器:
//1.在JSP中写java小脚本获取Cookie中存储的用户名和密码
//2.将用户名和密码使用输出表达式显示在输入框中
--%>
<%
//1.在JSP中写java小脚本获取Cookie中存储的用户名和密码
Cookie[] cookies = request.getCookies();
Cookie usernameCookie = CookieUtils.getCookie(cookies, "username");
Cookie passwordCookie = CookieUtils.getCookie(cookies, "password");
String username = usernameCookie==null?"":usernameCookie.getValue();
String password = passwordCookie==null?"":passwordCookie.getValue();
%>
用户登录
用户勾选了记住用户名复选框,我们把用户名存到Cookie里面,并设置有效时间
在index.jsp里面 从cookie取出用户名展示
String remember = request.getParameter("remember");
//登录成功
Cookie cookie = new Cookie("username", username);
if(remember!=null && remember.equals("on")){
//如果勾上记住用户名 将用户名保存在cookie中 并设置有效时间7天
cookie.setMaxAge(60*60*24*7);
}else{
//如果没有勾上记住用户名 就删除这个cookie
cookie.setMaxAge(0);
}
response.addCookie(cookie);
==JSP(全称:Java Server Pages):Java 服务端页面。==是一种动态的网页技术,其中既可以定义 HTML、JS、CSS等静态内容,还可以定义 Java代码的动态内容,也就是 JSP = HTML + Java
。如下就是jsp代码
Title
JSP,Hello World
<%
System.out.println("hello,jsp~");
%>
动态数据使用 Java 代码进行展示;这样操作看起来要比用 servlet
实现要舒服很多。
JSP 作用:简化开发,避免了在Servlet中直接输出HTML标签。
接下来我们做一个简单的快速入门代码。
创建一个maven的 web 项目
pom.xml
文件内容如下:
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>jsp-demoartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
plugin>
plugins>
build>
project>
在 dependencies
标签中导入 JSP 的依赖,如下
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
该依赖的 scope
必须设置为 provided
,因为 tomcat 中有这个jar包了,所以在打包时我们是不希望将该依赖打进到我们工程的war包中。
在项目的 webapp
下创建jsp页面
通过上面方式创建一个名为 hello.jsp
的页面。
在 hello.jsp
页面中书写 HTML
标签和 Java
代码,如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
hello jsp
<%
System.out.println("hello,jsp~");
%>
启动服务器并在浏览器地址栏输入 http://localhost:8080/jsp-demo/hello.jsp
同时也可以看到在 idea
的控制台看到输出的 hello,jsp~
内容。
我们之前说 JSP 就是一个页面,那么在 JSP 中写 html
标签,我们能理解,但是为什么还可以写 Java
代码呢?
因为 ==JSP 本质上就是一个 Servlet。==接下来我们聊聊访问jsp时的流程
hello.jsp
页面tomcat
会将 hello.jsp
转换为名为 hello_jsp.java
的一个 Servlet
tomcat
再将转换的 servlet
编译成字节码文件 hello_jsp.class
tomcat
会执行该字节码文件,向外提供服务JSP脚本用于在 JSP页面内定义 Java代码。在之前的入门案例中我们就在 JSP 页面定义的 Java 代码就是 JSP 脚本。
JSP 脚本有如下三个分类:
代码演示:
在 hello.jsp
中书写
<%
System.out.println("hello,jsp~");
int i = 3;
%>
通过浏览器访问 hello.jsp
后,查看转换的 hello_jsp.java
文件,i 变量定义在了 _jspService()
方法中
在 hello.jsp
中书写
<%="hello"%>
<%=i%>
通过浏览器访问 hello.jsp
后,查看转换的 hello_jsp.java
文件,该脚本的内容被放在了 out.print()
中,作为参数
在 hello.jsp
中书写
<%!
void show(){}
String name = "zhangsan";
%>
通过浏览器访问 hello.jsp
后,查看转换的 hello_jsp.java
文件,该脚本的内容被放在了成员位置
使用JSP脚本展示品牌数据
说明:
资料\1. JSP案例素材
中提供了 brand.html
静态页面将资料 资料\1. JSP案例素材
中的 Brand.java
文件放置到项目的 com.itheima.pojo
包下
在项目的 webapp
中创建 brand.jsp
,并将 brand.html
页面中的内容拷贝过来。brand.jsp
内容如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
序号
品牌名称
企业名称
排序
品牌介绍
状态
操作
1
三只松鼠
三只松鼠
100
三只松鼠,好吃不上火
启用
修改 删除
2
优衣库
优衣库
10
优衣库,服适人生
禁用
修改 删除
3
小米
小米科技有限公司
1000
为发烧而生
启用
修改 删除
现在页面中的数据都是假数据。
在 brand.jsp
中准备一些数据
<%
// 查询数据库
List brands = new ArrayList(); //检查用的是jdk1.5,后面的泛型必须要写
brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));
brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0));
brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1));
%>
==注意:==这里的类是需要导包的
将 brand.jsp
页面中的 table
标签中的数据改为动态的
序号
品牌名称
企业名称
排序
品牌介绍
状态
操作
<%
for (int i = 0; i < brands.size(); i++) {
//获取集合中的 每一个 Brand 对象
Brand brand = brands.get(i);
}
%>
1
三只松鼠
三只松鼠
100
三只松鼠,好吃不上火
启用
修改 删除
上面的for循环需要将 tr
标签包裹起来,这样才能实现循环的效果,代码改进为
序号
品牌名称
企业名称
排序
品牌介绍
状态
操作
<%
for (int i = 0; i < brands.size(); i++) {
//获取集合中的 每一个 Brand 对象
Brand brand = brands.get(i);
%>
1
三只松鼠
三只松鼠
100
三只松鼠,好吃不上火
启用
修改 删除
<%
}
%>
注意:<%%> 里面写的是 Java 代码,而外边写的是 HTML 标签
上面代码中的 td
标签中的数据都需要是动态的,所以还需要改进
序号
品牌名称
企业名称
排序
品牌介绍
状态
操作
<%
for (int i = 0; i < brands.size(); i++) {
//获取集合中的 每一个 Brand 对象
Brand brand = brands.get(i);
%>
<%=brand.getId()%>
<%=brand.getBrandName()%>
<%=brand.getCompanyName()%>
<%=brand.getOrdered()%>
<%=brand.getDescription()%>
<%=brand.getStatus() == 1 ? "启用":"禁用"%>
修改 删除
<%
}
%>
<%@ page import="com.itheima.pojo.Brand" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 查询数据库
List brands = new ArrayList();
brands.add(new Brand(1,"三只松鼠","三只松鼠",100,"三只松鼠,好吃不上火",1));
brands.add(new Brand(2,"优衣库","优衣库",200,"优衣库,服适人生",0));
brands.add(new Brand(3,"小米","小米科技有限公司",1000,"为发烧而生",1));
%>
Title
序号
品牌名称
企业名称
排序
品牌介绍
状态
操作
<%
for (int i = 0; i < brands.size(); i++) {
Brand brand = brands.get(i);
%>
<%=brand.getId()%>
<%=brand.getBrandName()%>
<%=brand.getCompanyName()%>
<%=brand.getOrdered()%>
<%=brand.getDescription()%>
<%=brand.getStatus() == 1 ? "启用":"禁用"%>
修改 删除
<%
}
%>
在浏览器地址栏输入 http://localhost:8080/jsp-demo/brand.jsp
通过上面的案例,我们可以看到 JSP 的很多缺点。
由于 JSP页面内,既可以定义 HTML 标签,又可以定义 Java代码,造成了以下问题:
书写麻烦:特别是复杂的页面
既要写 HTML 标签,还要写 Java 代码
阅读麻烦
上面案例的代码,相信你后期再看这段代码时还需要花费很长的时间去梳理
复杂度高:运行需要依赖于各种环境,JRE,JSP容器,JavaEE…
占内存和磁盘:JSP会自动生成.java和.class文件占磁盘,运行的是.class文件占内存
调试困难:出错后,需要找到自动生成的.java文件进行调试
不利于团队协作:前端人员不会 Java,后端人员不精 HTML
如果页面布局发生变化,前端工程师对静态页面进行修改,然后再交给后端工程师,由后端工程师再将该页面改为 JSP 页面
由于上述的问题, ==JSP 已逐渐退出历史舞台,==以后开发更多的是使用 HTML + Ajax 来替代。Ajax 是我们后续会重点学习的技术。有个这个技术后,前端工程师负责前端页面开发,而后端工程师只负责前端代码开发。下来对技术的发展进行简单的说明
第一阶段:使用 servlet
即实现逻辑代码编写,也对页面进行拼接。这种模式我们之前也接触过
第二阶段:随着技术的发展,出现了 JSP
,人们发现 JSP
使用起来比 Servlet
方便很多,但是还是要在 JSP
中嵌套 Java
代码,也不利于后期的维护
第三阶段:使用 Servlet
进行逻辑代码开发,而使用 JSP
进行数据展示
第四阶段:使用 servlet
进行后端逻辑代码开发,而使用 HTML
进行数据展示。而这里面就存在问题,HTML
是静态页面,怎么进行动态数据展示呢?这就是 ajax
的作用了。
那既然 JSP 已经逐渐的退出历史舞台,那我们为什么还要学习 JSP
呢?原因有两点:
JSP
,所以要求我们必须动 JSP
接下来我们来学习第三阶段,使用 EL表达式
和 JSTL
标签库替换 JSP
中的 Java
代码。
EL(全称Expression Language )表达式语言,用于简化 JSP 页面内的 Java 代码。
EL 表达式的主要作用是 获取数据。其实就是从域对象中获取数据,然后将数据展示在页面上。
而 EL 表达式的语法也比较简单,== e x p r e s s i o n = = 。例如: {expression}== 。例如: expression==。例如:{brands} 就是获取域中存储的 key 为 brands 的数据。
定义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" %>
Title
${brands}
//获取集合中对象的属性值: ${brands[下标].属性名}
JavaWeb中有四大域对象(数据的作用域),分别是:
el 表达式获取数据,会依次从这4个域中寻找(先从小范围找,再到大范围找),直到找到为止。
例如: ${brands},el 表达式获取数据,会先从page域对象中获取数据,如果没有再到 requet 域对象中获取数据,如果再没有再到 session 域对象中获取,如果还没有才会到 application 中获取数据。
<%@ page import="bean.User" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
1. 使用EL表达式取简单的数据
<%--语法: ${KEY}--%>
<%--
1. 要想使用EL表达式取值,就必须先往作用域里面存值。
2. 存值的时候,可以直接在页面上存值,也可以选择在servlet里面存值,然后跳转到jsp页面来取值展示
3. 在jsp页面上,是有4个内置的作用域对象,直接使用即可不需要创建他们
--%>
2. 使用EL表达式取作用域中的值
<%--
1. 依次从小到大取值。
2. 作用域范围: page --- request --- session --- application
3. 也可以指定具体的范围去找数据
${pageScope.name}=
${requestScope.name}
${sessionScope.name}
${applicationScope.name}
--%>
${name}
=${pageScope.name}=
<%--${requestScope.name}
${sessionScope.name}
${applicationScope.name}--%>
3. 使用EL表达式取集合的数据
<%--语法: ${KEY[下标].属性}--%>
<%
List list = new ArrayList();
list.add(new User(1 , "admin" , "123456")) ;
list.add(new User(2 , "zhangsan" , "6666")) ;
request.setAttribute("list", list);
%>
${list[1].username} , ${list[1].password}
JSP标准标签库(Jsp Standarded Tag Library) ,使用标签取代JSP页面上的Java代码。如下代码就是JSTL标签
JSTL的标签,通常是和作用域的数据挂钩的。也就是说,它一般是用来处理作用域的值
男
女
上面代码看起来是不是比 JSP 中嵌套 Java 代码看起来舒服好了。而且前端工程师对标签是特别敏感的,他们看到这段代码是能看懂的。
JSTL 提供了很多标签,两个最常用的标签,
标签和
标签。
JSTL 使用也是比较简单的,分为如下步骤:
导入坐标
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
在JSP页面上引入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
//c其实就是代表用的标签的前缀,如果写成了abc,那下面的标签都要改变成
使用标签
:相当于 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
页面,在该页面使用
标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
<%--
c:if:来完成逻辑判断,替换java if else
--%>
启用
禁用
注意: 在该页面已经要引入 JSTL核心标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
:相当于 for 循环。java中有增强for循环和普通for循环,JSTL 中的
也有两种用法
类似于 Java 中的增强for循环。涉及到的
中的属性如下
如下代码,是从域对象中获取名为 brands 数据,该数据是一个集合;遍历遍历,并给该集合中的每一个元素起名为 brand
,是 Brand对象。在循环里面使用 EL表达式获取每一个Brand对象的属性值
${brand.id}
${brand.brandName}
${brand.companyName}
${brand.description}
代码演示:
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" %>
Title
序号
品牌名称
企业名称
排序
品牌介绍
状态
操作
<%--${brand.id} --%>
${status.count}
${brand.brandName}
${brand.companyName}
${brand.ordered}
${brand.description}
启用
禁用
修改 删除
类似于 Java 中的普通for循环。涉及到的
中的属性如下
begin:开始数
end:结束数
step:步长
实例代码:
从0循环到10,变量名是 i
,每次自增1
${i}
MVC 模式和三层架构是一些理论的知识,将来我们使用了它们进行代码开发会让我们代码维护性和扩展性更好。
MVC 是一种分层开发的模式,其中:
M:Model,业务模型,处理业务
V:View,视图,界面展示
C:Controller,控制器,处理请求,调用模型和视图
控制器(serlvlet)用来接收浏览器发送过来的请求,控制器调用模型(JavaBean)来获取数据,比如从数据库查询数据;控制器获取到数据后再交由视图(JSP)进行数据展示。
MVC 好处:
职责单一,互不影响。每个角色做它自己的事,各司其职。
有利于分工协作。
有利于组件重用
三层架构是将我们的项目分成了三个层面,分别是 表现层
、业务逻辑层
、数据访问层
。
注册业务功能
,我们会先调用 数据访问层
的 selectByName()
方法判断该用户名是否存在,如果不存在再调用 数据访问层
的 insert()
方法进行数据的添加操作而整个流程是,浏览器发送请求,表现层的Servlet接收请求并调用业务逻辑层的方法进行业务逻辑处理,而业务逻辑层方法调用数据访问层方法进行数据的操作,依次返回到serlvet,然后servlet将数据交由 JSP 进行展示。
三层架构的每一层都有特有的包名称:
com.itheima.controller
或者 com.itheima.web
com.itheima.service
com.itheima.dao
或者 com.itheima.mapper
后期我们还会学习一些框架,不同的框架是对不同层进行封装的
通过 MVC 和 三层架构 的学习,有些人肯定混淆了。那他们有什么区别和联系?
MVC 模式
中的 C(控制器)和 V(视图)就是 三层架构
中的表现层,而 MVC 模式
中的 M(模型)就是 三层架构
中的 业务逻辑层 和 数据访问层。
可以将 MVC 模式
理解成是一个大的概念,而 三层架构
是对 MVC 模式
实现架构的思想。 那么我们以后按照要求将不同层的代码写在不同的包下,每一层里功能职责做到单一,将来如果将表现层的技术换掉,而业务逻辑层和数据访问层的代码不需要发生变化。
需求:完成品牌数据的增删改查操作
这个功能我们之前一直在做,而这个案例是将今天学习的所有的内容(包含 MVC模式 和 三层架构)进行应用,并将整个流程贯穿起来。
环境准备工作,我们分以下步骤实现:
创建新的模块 brand_demo,引入坐标
创建三层架构的包结构
数据库表 tb_brand
实体类 Brand
MyBatis 基础环境
Mybatis-config.xml
BrandMapper.xml
BrandMapper接口
创建新的模块 brand_demo,引入坐标。我们只要分析出要用到哪儿些技术,那么需要哪儿些坐标也就明确了
pom.xml
内容如下:
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>brand-demoartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.34version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>taglibsgroupId>
<artifactId>standardartifactId>
<version>1.1.2version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
plugin>
plugins>
build>
project>
创建不同的包结构,用来存储不同的类。
-- 删除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);
在 pojo
包下创建名为 Brand
的类。
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 +
'}';
}
}
定义核心配置文件 Mybatis-config.xml
,并将该文件放置在 resources
下
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 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>
<package name="com.itheima.mapper"/>
mappers>
configuration>
在 resources
下创建放置映射配置文件的目录结构 com/itheima/mapper
,并在该目录下创建映射配置文件 BrandMapper.xml
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>
当我们点击 index.html
页面中的 查询所有
这个超链接时,就能查询到数据。
对于上述的功能,点击 查询所有
超链接是需要先请后端的 servlet
,由 servlet
跳转到对应的页面进行数据的动态展示。
在 mapper
包下创建创建 BrandMapper
接口,在接口中定义 selectAll()
方法
/**
* 查询所有
* @return
*/
@Select("select * from tb_brand")
List<Brand> selectAll();
在 com.itheima
包下创建 utils
包,并在该包下创建名为 SqlSessionFactoryUtils
工具类
public class SqlSessionFactoryUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
//静态代码块会随着类的加载而自动执行,且只执行一次
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
在 service
包下创建 BrandService
类
public class BrandService {
SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();
/**
* 查询所有
* @return
*/
public List<Brand> selectAll(){
//调用BrandMapper.selectAll()
//2. 获取SqlSession
SqlSession sqlSession = factory.openSession();
//3. 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
//4. 调用方法
List<Brand> brands = mapper.selectAll();
sqlSession.close();
return brands;
}
}
在 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);
}
}
brand.jsp
页面在表格中使用 JSTL
和 EL表达式
从request域对象中获取名为 brands
的集合数据并展示出来。页面内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Title
序号
品牌名称
企业名称
排序
品牌介绍
状态
操作
<%--${brand.id} --%>
${status.count}
${brand.brandName}
${brand.companyName}
${brand.ordered}
${brand.description}
启用
禁用
修改 删除
启动服务器,并在浏览器输入 http://localhost:8080/brand-demo/index.html
,看到如下 查询所有
的超链接,点击该链接就可以查询出所有的品牌数据
为什么出现这个问题呢?是因为查询到的字段名和实体类对象的属性名没有一一对应。相比看到这大家一定会解决了,就是在映射配置文件中使用 resultMap
标签定义映射关系。映射配置文件内容如下:
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="brandResultMap" type="brand">
<result column="brand_name" property="brandName">result>
<result column="company_name" property="companyName">result>
resultMap>
mapper>
并且在 BrandMapper
接口中的 selectAll()
上使用 @ResuleMap
注解指定使用该映射
/**
* 查询所有
* @return
*/
@Select("select * from tb_brand")
@ResultMap("brandResultMap")
List<Brand> selectAll();
重启服务器,再次访问就能看到我们想要的数据了
点击 新增
按钮后,会先跳转到 addBrand.jsp
新增页面,在该页面输入要添加的数据,输入完毕后点击 提交
按钮,需要将数据提交到后端,而后端进行数据添加操作,并重新将所有的数据查询出来。
接下来我们根据流程来实现功能:
在 BrandMapper
接口,在接口中定义 add(Brand brand)
方法
@Insert("insert into tb_brand values(null,#{brandName},#{companyName},#{ordered},#{description},#{status})")
void add(Brand brand);
在 BrandService
类中定义添加品牌数据方法 add(Brand brand)
/**
* 添加
* @param brand
*/
public void add(Brand brand){
//2. 获取SqlSession
SqlSession sqlSession = factory.openSession();
//3. 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
//4. 调用方法
mapper.add(brand);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
我们需要在该页面表格的上面添加 新增
按钮
<input type="button" value="新增" id="add"><br>
并给该按钮绑定单击事件,当点击了该按钮需要跳转到 brand.jsp
添加品牌数据的页面
<script>
document.getElementById("add").onclick = function (){
location.href = "/brand-demo/addBrand.jsp";
}
script>
==注意:==该
script
标签建议放在body
结束标签前面。
从资料 资料\2. 品牌增删改查案例\静态页面
中将 addBrand.html
页面拷贝到项目的 webapp
下,并改成 addBrand.jsp
动态页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
添加品牌
添加品牌
在 web
包下创建 AddServlet
的 servlet
,该 servlet
的逻辑如下:
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 注意,如果这里用请求转发,那么地址栏不变,每次刷新都会新增一条一模一样的数据,这是有问题的,所以必须要重定向到查询所有的界面
response.sendRedirect("/selectAllServlet").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
点击 brand.jsp
页面的 新增
按钮,会跳转到 addBrand.jsp
页面
点击 提交
按钮,就能看到如下页面,里面就包含我们刚添加的数据
点击每条数据后面的 编辑
按钮会跳转到修改页面
在该修改页面我们可以看到将 编辑
按钮所在行的数据 回显 到表单,然后需要修改那个数据在表单中进行修改,然后点击 提交
的按钮将数据提交到后端,后端再将数据存储到数据库中。
从上面的例子我们知道 修改
功能需要从两方面进行实现,数据回显和修改操作。
要实现这个效果,那当点击 修改
按钮时不能直接跳转到 update.jsp
页面,而是需要先带着当前行数据的 id
请求后端程序,后端程序根据 id
查询数据,将数据存储到域对象中跳转到 update.jsp
页面进行数据展示。
在 BrandMapper
接口,在接口中定义 selectById(int id)
方法
/**
* 根据id查询
* @param id
* @return
*/
@Select("select * from tb_brand where id = #{id}")
@ResultMap("brandResultMap")
Brand selectById(int id);
在 BrandService
类中定义根据id查询数据方法 selectById(int id)
/**
* 根据id查询
* @return
*/
public Brand selectById(int id){
//调用BrandMapper.selectAll()
//2. 获取SqlSession
SqlSession sqlSession = factory.openSession();
//3. 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
//4. 调用方法
Brand brand = mapper.selectById(id);
sqlSession.close();
return brand;
}
在 web
包下创建 SelectByIdServlet
的 servlet
,该 servlet
的逻辑如下:
id
BrandService
的 selectById()
方法进行数据查询的业务逻辑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);
}
}
拷贝 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" %>
修改品牌
修改品牌
做完回显数据后,接下来我们要做修改数据了
在修改页面进行数据修改,点击 提交
按钮,会将数据提交到后端程序,后端程序会对表中的数据进行修改操作,然后重新进行数据的查询操作。
在 BrandMapper
接口,在接口中定义 update(Brand brand)
方法
/**
* 修改
* @param brand
*/
@Update("update tb_brand set brand_name = #{brandName},company_name = #{companyName},ordered = #{ordered},description = #{description},status = #{status} where id = #{id}")
void update(Brand brand);
在 BrandService
类中定义根据id查询数据方法 update(Brand brand)
/**
* 修改
* @param brand
*/
public void update(Brand brand){
//2. 获取SqlSession
SqlSession sqlSession = factory.openSession();
//3. 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
//4. 调用方法
mapper.update(brand);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
}
在 web
包下创建 AddServlet
的 servlet
,该 servlet
的逻辑如下:
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 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));
//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);
}
}
存在问题:update.jsp 页面提交数据时是没有携带主键数据的,而后台修改数据需要根据主键进行修改。
针对这个问题,我们不希望页面将主键id展示给用户看,但是又希望在提交数据时能将主键id提交到后端。此时我们就想到了在学习 HTML 时学习的隐藏域,在 update.jsp
页面的表单中添加如下代码:
<%--隐藏域,提交id--%>
update.jsp
页面的最终代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
修改品牌
修改品牌