JSP
-
定义
- JSP(Java Server Pages),即Java服务端页面。
- 它是一种动态的网页技术,其中可以定义HTML、CSS、JS等静态内容,还可以定义Java代码的动态内容
- JSP = HTML + Java
- 说白了JSP就是一个页面,它既可以写HTML标签,又可以写Java代码
-
简单示例
jsp"><%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>Title</title></head><body><h1>JSP,HELLO WORLD!!!</h1><%System.out.println("Hello JSP");%></body> </html>
JSP快速入门
-
步骤
-
Step1:在pom.xml文件中导入JSP坐标依赖
- JSP坐标需要设置坐标依赖范围为
provided
,即该坐标在编译和测试时有效-
因为Tomcat中已经提供好了JSP的jar包,所以在打包后应该排除掉自己所设置的jar包,若不排除则会报错
-
注意Servlet坐标依赖也是需要设置坐标依赖范围为
provided
,原因与其相同
-
- JSP坐标需要设置坐标依赖范围为
-
<dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope>
</dependency>
- 完整pom.xml文件如下```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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>JspDemo</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>JspDemo Maven Webapp</name><url>http://maven.apache.org</url><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!--JSP坐标依赖 注意别忘了加上坐标依赖范围--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope></dependency></dependencies><build><finalName>JspDemo</finalName><plugins><!-- Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins></build></project>```
-
Step2:创建JSP文件
- 注意:不能将JSP文件放到webapp目录下的WEB-INF目录下,因为该目录不能通过浏览器直接访问到,应该直接放到webapp目录下
-
Step3:编写HTML标签和Java代码(该步骤省略可详见JSP快速入门)
- Java代码被包裹在
<% 这中间写Java代码 %>
中间
- Java代码被包裹在
JSP原理
-
JSP本质上就是一个Servlet。
- JSP在被访问时,由JSP容器(即Tomcat)将其转换为Java文件(即Servlet),然后在由JSP容器(即Tomcat)将其编译,最终对外提供服务的其实就是这个字节码文件
-
详解如下
-
JSP工作流程
- 编写 JSP 页面: 开发者编写一个 JSP 页面,包含 HTML 和嵌入的 Java 代码。
- 编译 JSP 页面: JSP 容器将 JSP 页面编译成一个 Java servlet 类,这个类继承自
HttpJspBase
。- 通过继承
HttpJspBase
,JSP 页面的 servlet 能够有效地利用 servlet 的生命周期方法,并且使 JSP 页面能够与 servlet 容器集成,处理 HTTP 请求和响应。
- 通过继承
- 初始化: 在 servlet 被加载时,容器调用
jspInit()
方法进行初始化。 - 处理请求: 每次请求到达时,容器调用 servlet 的
service()
方法,进而调用_jspService()
方法来处理请求。 - 销毁: 当 servlet 被卸载时,容器调用
jspDestroy()
方法进行清理。
-
示例(以JSP快速入门的hello.jsp文件为例),hello.jsp代码如下
jsp"><%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>Title</title></head><body><h1>JSP,HELLO WORLD!!!</h1><%System.out.println("Hello JSP");%></body> </html>
-
Step1:代开当前Web项目的目录
-
Step2:打开当前项目目录下的target目录→tomcat→work→然后一直进入到jsp目录下
-
Step3:会发现有一个java文件,该文件就是JSP文件所生成的对应Java文件,打开该hello_jsp.java文件,代码如下
java">package org.apache.jsp;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*;public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBaseimplements org.apache.jasper.runtime.JspSourceDependent {private static final javax.servlet.jsp.JspFactory _jspxFactory =javax.servlet.jsp.JspFactory.getDefaultFactory();private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;private javax.el.ExpressionFactory _el_expressionfactory;private org.apache.tomcat.InstanceManager _jsp_instancemanager;public java.util.Map<java.lang.String,java.lang.Long> getDependants() {return _jspx_dependants;}public void _jspInit() {_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());}public void _jspDestroy() {}public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {final javax.servlet.jsp.PageContext pageContext;javax.servlet.http.HttpSession session = null;final javax.servlet.ServletContext application;final javax.servlet.ServletConfig config;javax.servlet.jsp.JspWriter out = null;final java.lang.Object page = this;javax.servlet.jsp.JspWriter _jspx_out = null;javax.servlet.jsp.PageContext _jspx_page_context = null;try {response.setContentType("text/html;charset=UTF-8");pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);_jspx_page_context = pageContext;application = pageContext.getServletContext();config = pageContext.getServletConfig();session = pageContext.getSession();out = pageContext.getOut();_jspx_out = out;out.write("\r\n");out.write("\r\n");out.write("<html>\r\n");out.write(" <head>\r\n");out.write(" <title>Title</title>\r\n");out.write(" </head>\r\n");out.write(" <body>\r\n");out.write(" <h1>JSP,HELLO WORLD!!!</h1>\r\n");out.write(" ");System.out.println("Hello JSP");out.write("\r\n");out.write(" </body>\r\n");out.write("</html>\r\n");} catch (java.lang.Throwable t) {if (!(t instanceof javax.servlet.jsp.SkipPageException)){out = _jspx_out;if (out != null && out.getBufferSize() != 0)try { out.clearBuffer(); } catch (java.io.IOException e) {}if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);else throw new ServletException(t);}} finally {_jspxFactory.releasePageContext(_jspx_page_context);}} }
-
-
对
HttpJspBase
类详解- 初始化和清理:
HttpJspBase
提供了jspInit()
和jspDestroy()
方法,分别对应 servlet 的init()
和destroy()
方法。这些方法允许 JSP 页面在初始化和销毁时执行特定的代码。 - 服务方法:
HttpJspBase
类会覆盖service()
方法,以便调用_jspService(HttpServletRequest request, HttpServletResponse response)
方法,这是每个 JSP 页面必须实现的一个方法,用于处理请求和生成响应。 - 编译过程: 当 JSP 页面被容器(如 Apache Tomcat)编译时,它会生成一个继承自
HttpJspBase
的 servlet 类。生成的 servlet 类会实现_jspService()
方法,该方法包含了 JSP 页面中的实际代码。
- 初始化和清理:
JSP脚本
-
作用:用于在JSP页面内定义Java代码
-
JSP脚本分类
分类 解释 <%...%>
内容会直接放到 _jspService()
方法之中<%=...%>
内容会放到 out.print()
之中,作为out.print()
的参数<%!...%>
内容会直接放到 _jspService()
方法之外,被类继续包含。即跟属性、方法属于同一级 -
示例
jsp"><%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>Title</title></head><body><h1>JSP,HELLO WORLD!!!</h1><!--第一种脚本--><%System.out.println("Hello JSP");int i = 3;%><!--第二种脚本--><%="i为" + 3%><!--第三种脚本--><%!void show(){}String name = "zhangsan";%></body> </html>
-
第一种脚本
<%...%>
,会在生成的java文件的_jspService()
方法之中,如下代码所示(注意:博主把该_jspService
方法内的无关代码均已删除,这样能清楚看出来该脚本内的代码在该方法之中)(html代码也在_jspService()
方法之中, 如下代码所示 )java">public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {try {out.write("\r\n");out.write("\r\n");out.write("<html>\r\n");out.write(" <head>\r\n");out.write(" <title>Title</title>\r\n");out.write(" </head>\r\n");out.write(" <body>\r\n");out.write(" <h1>JSP,HELLO WORLD!!!</h1>\r\n");out.write(" <!--第一种脚本-->\r\n");out.write(" ");System.out.println("Hello JSP");int i = 3;out.write("\r\n");out.write(" <!--第二种脚本-->\r\n");out.write(" ");out.print("i为" + i);out.write("\r\n");out.write(" <!--第三种脚本-->\r\n");out.write(" ");out.write("\r\n");out.write(" </body>\r\n");out.write("</html>\r\n");} }
-
第二种脚本
<%=...%>
,也会在生成的java文件的_jspService()
方法之中,不过它的内容会放到out.print()
之中,作为out.print()
的参数,最终输出到页面上,代码详见第一种脚本处的代码,Tomcat运行该Web项目后,页面显示如下 -
第三种脚本
<%!...%>
,内容会直接放到_jspService()
方法之外,被类继续包含。即跟属性、方法属于同一级,如下所示(注意:代码均为省略形式,以便明了)java">public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBaseimplements org.apache.jasper.runtime.JspSourceDependent {void show(){}String name = "zhangsan"; }
-
JSP脚本示例
-
将数据库中的商品显示在浏览器页面
-
brand对象类
java">package at.guigu.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, 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;}@Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';} }
-
brand.jsp文件
jsp"><%@ page import="at.guigu.pojo.Brand" %> <%@ page import="java.util.ArrayList" %> <%@ page import="java.util.List" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %><%//模拟查询数据库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)); %><!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><%for (int i = 0; i < brands.size(); i++) {Brand brand = brands.get(i);//获取第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><%if (brand.getStatus() == 0) {%><%="禁用"%><%}else {%><%="启用"%><%}%></td><td><a href="#">修改</a> <a href="#">删除</a></td></tr><%}%></table></body> </html>
-
注意以下这一部分代码可改为
jsp"><td><%if (brand.getStatus() == 0) {%><%="禁用"%><%}else {%><%="启用"%><%}%> </td> <!--等同于--> <%if (brand.getStatus() == 0) { %><td><%="禁用"%></td> <%}else { %><td><%="启用"%></td> <%} %>
Tomcat运行该Web项目后页面运行截图如下
-
-
-
注意事项
-
在JSP文件中Java代码可跟Html代码可嵌套来写,但是Java代码要写在JSP脚本中,Html代码不能写在脚本中,如下所示
- 嵌套方式来写java和html代码比较麻烦,对于复杂的页面不利于阅读和调试等工作,所以最好不要在JSP中直接写Java代码
jsp"><%if (brand.getStatus() == 0) { %><td><%="禁用"%></td> <%}else { %><td><%="启用"%></td> <%} %>
-
JSP缺点
-
列举部分缺点如下:
-
解决方式
- 不直接在JSP中写Java代码,而是利用Servlet和JSP的结合(即Java代码写在Servlet中,进行逻辑处理,封装数据;而JSP利用EL表达式 和JSTL标签 来获取数据并进行遍历展现数据)
- EL表达式: 用来替换JSP中获取数据的Java代码
- JSTL标签: 用来替换循环、遍历的Java代码
- 不直接在JSP中写Java代码,而是利用Servlet和JSP的结合(即Java代码写在Servlet中,进行逻辑处理,封装数据;而JSP利用EL表达式 和JSTL标签 来获取数据并进行遍历展现数据)
EL表达式
-
定义
- Expression Language表达式语言,用于简化JSP页面内的Java代码
-
主要功能:获取数据
-
语法:
${key}
${brands}
:获取request
域中存储的key为brands的数据
-
JavaWeb中四大域对象
- page:当前页面有效
- request:当前请求有效
- session:当前会话有效
- application:当前应用有效
- 注意:EL表达式获取数据时会依次从这4个域中寻找,直到找到为止
-
简单示例
-
Step1:在at.guigu.web包下创建
ServletDemo1
类,将准备数据放入,最终代码如下java">package at.guigu.web;import at.guigu.pojo.Brand;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.util.ArrayList; import java.util.List;@WebServlet("/eldemo1") public class ServletDemo1 extends HttpServlet {@Overrideprotected 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.jsprequest.getRequestDispatcher("/el-demo.jsp").forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
-
Step2:创建el-demo.jsp文件,具体代码如下
- 注意:要在JSP页面顶部
<%@...%>
标签体内加上isELIgnored="false"
,作用是防止Tomcat配置禁用EL表达式
jsp"><%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><!--获取request域中存储brands的数据-->${brands}</body> </html>
Tomcat运行该Web项目后运行截图如下
- 注意:要在JSP页面顶部
-
JSTL标签
-
定义
- JSTL(即JSP Standarded Tag Library),是Java 服务器页面标准标签库,使用标签取代JSP页面上的Java代码
- 它为 JSP 页面提供了一组标准的标签库,用于简化 JSP 页面中的常见任务,例如条件判断、循环迭代、字符串操作、国际化、数据库访问等。
-
JSTL标签
标签 解释 <c:out>
用于在JSP中显示数据,相当于 <%=...>
<c:set>
用于保存数据 <c:remove>
用于删除数据 <c:catch>
用来处理产生错误的异常情况,并将错误信息储存起来 <c:if>
与java中的if一样 <c:choose>
本身只当作 <c:when>
和<c:otherwise>
的父标签<c:when>
<c:choose>
的子标签,用来判断条件是否成立<c:otherwise>
<c:choose>
的子标签,接在<c:when>
标签后,当<c:when>
标签判断为false时被执行<c:import>
检索一个绝对或相对URL,然后将其内容暴露给页面 <c:forEach>
基础迭代标签,接受多种集合类型 <c:forTokens>
根据指定的分隔符来分割内容并迭代输出 <c:param>
用来给包含或重定向的页面传递参数 <c:redirect>
重定向至一个新的URL <c:url>
使用可选的查询参数来创造一个URL -
JSTL标签使用步骤
-
Step1: 在Web项目的pom.xml文件中导入坐标依赖
<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>
-
Step2: 在JSP页面上引入JSTL标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
,如下所示jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>Title</title></head><body></body> </html>
-
Step3: 使用标签
-
使用标签—条件标签
<c:if>
标签
- 定义:相当于if判断
该标签中必有的属性 | 解释 |
---|---|
test | 该属性的属性值为逻辑表达式,结果若为true则执行该标签体中的内容 |
-
简单示例,jstl-demo1.jsp文件代码如下
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>Title</title></head><body><c:if test="true"><h1>判断为true</h1></c:if></body> </html>
-
<c:if>
标签通常与EL表达式联合使用来执行对应的代码,代码示例如下-
ServletDemo1.java代码如下
java">package at.guigu.web;import at.guigu.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("/jstldemo2") public class ServletDemo2 extends HttpServlet {@Overrideprotected 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);//用来测试<c:if>标签request.setAttribute("status", 1);//3 转发到el-demo.jsprequest.getRequestDispatcher("/jstl-demo2.jsp").forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
-
jstl-demo2.jsp文件代码如下:
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><c:if test="${status==1}"><h1>满足status==1则输出该条html语句</h1></c:if></body> </html>
-
<c:choose>
、<c:when>
、<c:otherwise>
-
以上三个标签联合使用用于实现多条件分支的逻辑控制,类似于 Java 中的
switch
语句或 if-else-if 结构。 -
三个标签解释
<c:choose>
- 该标签本身没有属性
- 可包含一个或多个
<c:when>
标签,可以选择性 地包含一个<c:otherwise>
标签
<c:when>
标签- 用于定义每个条件分支
- 具有唯一的必需属性
test
<c:otherwise>
标签- 用于定义在所有
<c:when>
条件都不满足时应该执行的代码块 - 该标签没有属性,且必须位于
<c:choose>
标签内,并且通常放在所有<c:when>
标签之后 - 该标签内的内容在所有
<c:when>
条件都为 false 时执行
- 用于定义在所有
-
代码示例1
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <c:choose><c:when test="${user.age < 18}"><p>您是未成年人。</p></c:when><c:when test="${user.age >= 18 and user.age <= 65}"><p>您是成年人。</p></c:when><c:otherwise><p>您是老年人。</p></c:otherwise> </c:choose>
- 如果
user.age
小于 18,则显示“您是未成年人。 - 如果
user.age
在 18 到 65 之间(含),则显示“您是成年人。 - 如果以上两个条件都不满足(即
user.age
大于 65),则显示“您是老年人。
- 如果
-
代码示例2
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <c:choose><c:when test="${user.role == 'admin'}"><p>欢迎管理员!</p></c:when><c:when test="${user.role == 'user'}"><p>欢迎普通用户!</p></c:when><c:otherwise><p>欢迎访客,请登录。</p></c:otherwise> </c:choose>
- 如果
user.role
是admin
,则显示“欢迎管理员!” - 如果
user.role
是user
,则显示“欢迎普通用户!” - 如果以上两个条件都不满足,则执行
<c:otherwise>
标签内的内容,显示“欢迎访客,请登录。
- 如果
使用标签------迭代标签<c:forEach>
该标签的属性 | 解释 |
---|---|
items | 要迭代的集合(即被遍历的容器)。可以是数组、集合、映射等 |
var | 每次迭代时存储当前项的变量名(即遍历产生的临时变量) |
varStatus | 一个变量,用于存储迭代状态(即遍历状态对象)(可选)(注意: 该属性的属性值字符串可随意写,属性值.index :序号从0开始;属性值.count :序号从1开始) |
begin | 迭代的起始索引(可选) |
end | 迭代的结束索引(可选) |
step | 每次迭代的步长(可选) |
- 定义:相当于for循环
增强for循环
-
增强for循环代码示例
-
Brand类代码
java">package at.guigu.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, 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;}@Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';} }
-
JstlServletDemo3代码
java">package at.guigu.web;import at.guigu.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("/jstldemo3") public class JstlServletDemo3 extends HttpServlet {@Overrideprotected 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);//用来测试<c:if>标签request.setAttribute("status", 1);//3 转发到el-demo.jsprequest.getRequestDispatcher("/jstl-demo3.jsp").forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
-
jstl-demo3.jsp代码
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><input type="button" value="新增"><br><hr><table border="1" cellspacing="0"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand"><tr align="center"><td>${brand.id}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:choose><c:when test="${brand.status==1}"><td>启用</td></c:when><c:otherwise><td>禁用</td></c:otherwise></c:choose><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach></table></body> </html>
-
-
注意
-
EL表达式
${对象名.属性名}
会被系统自动解析并调用对应的getXXX()
方法来返回对应的值 -
上述运行截图中序号对应的是数据库中的主键id,这就会有一个弊端,如果删除优衣库则由于主键是唯一的,不会分配给其它品牌,所以最终浏览器的页面上的品牌三只松鼠和小米的序号仍为1、3,并不会变成1、2
-
为了解决该问题可使用
varStatus
属性,如下jsp文件代码所示示例一:序号从0开始
jsp"><%--Created by IntelliJ IDEA.User: 10195Date: 2024/6/28Time: 9:19To change this template use File | Settings | File Templates. --%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><input type="button" value="新增"><br><hr><table border="1" cellspacing="0"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="xuhao"><tr align="center"><td>${xuhao.index}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:choose><c:when test="${brand.status==1}"><td>启用</td></c:when><c:otherwise><td>禁用</td></c:otherwise></c:choose><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach></table></body> </html>
示例二:序号从1开始
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><input type="button" value="新增"><br><hr><table border="1" cellspacing="0"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="xuhao"><tr align="center"><td>${xuhao.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:choose><c:when test="${brand.status==1}"><td>启用</td></c:when><c:otherwise><td>禁用</td></c:otherwise></c:choose><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach></table></body> </html>
-
-
普通for循环
-
作用:可用来定义分页工具条
-
代码示例
-
Brand及JstlServletDemo3代码与增强for循环一样,此处省略
-
jstl-demo3.jsp代码
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><input type="button" value="新增"><br><hr><table border="1" cellspacing="0"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="xuhao"><tr align="center"><td>${xuhao.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:choose><c:when test="${brand.status==1}"><td>启用</td></c:when><c:otherwise><td>禁用</td></c:otherwise></c:choose><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach></table><hr><c:forEach begin="1" end="10" step="1" var="i"><a href="#">${i}</a></c:forEach></body> </html>
-
理论知识
MVC模式
-
定义:MVC是一种分层开发的模式
- M(Model):即业务模型,用于处理业务
- V(View):即视图,用于页面展示
- C(Controller):即控制器,用于处理请求,调用模型和视图
-
MVC模式实现过程
浏览器向服务器端请求数据时会先请求控制器,控制器调用模型来获取数据,之后控制器会将数据传给视图,并由视图响应给浏览器,实现最终的页面展示
-
特点
- 由Servlet充当控制器,JavaBean充当模型,JSP充当视图
- 职责单一,互不影响
- 有利于分工协作
- 有利于组件重用
三层架构
-
解释:将一个完整的项目分为三个层面
- 表现层:接收请求,封装数据,调用业务逻辑层,响应数据
- 包名默认为:
at.guigu.web
或at.guigu.controller
- 对应的框架为:
SpringMVC
或Struts2
- 包名默认为:
- 业务逻辑层:对业务逻辑进行封装,组合数据访问层层中的基本功能,从而形成复杂的业务逻辑功能
- 包名默认为:
at.guigu.service
- 对应的框架为:
Spring
- 解释:假设现在数据访问层有多个增删改查方法,若表现层有多个实现Servlet的类需要用到其中增和删两个方法,此时若在实现类中频繁写重复代码就造成了冗余,所以我们可以将其封装起来作为一个业务方法,以此来供实现Servlet接口的实现类使用,这样可增加代码的复用性
- 包名默认为:
- 数据访问层(持久层):对数据库进行CRUD(增删改查)的基本操作
- 包名默认为:
at.guigu.dao
或at.guigu.mapper
- 若我们用到了MyBatis技术则使用后者,反之使用前者
- 对应的框架为:
MyBatis
或Hibername
- 包名默认为:
- 表现层:接收请求,封装数据,调用业务逻辑层,响应数据
-
三层架构实现过程
浏览器向服务器端请求数据时会先请求表现层的控制器(即Servlet),然后控制器会调用业务逻辑层的代码(这些代码组装了数据访问层的CRUD等基本功能)来获取数据库中的数据,并将数据返回给表现层中的控制器(即Swervlet),然后再由控制器(即Servlet)对数据进行封装,放到request域中传给视图(即JSP),最终由视图(即JSP)将响应数据返回给浏览器,使其展现在页面上
-
MVC模式和三层架构的区别
案例
注意:本案例已提交到Gitee,可自行下载:https://gitee.com/cgrs572/brand-demo.git
环境准备
-
创建新的Web项目BrandDemo,引入坐标(在pom.xml文件中引入坐标依赖),并配置Tomcat(可详见Tomcat部分)
-
需要的坐标依赖有mybatis、mysql驱动、servlet、jsp、jstl
-
需要的插件有Tomcat插件
-
完整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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>BrandDemo</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>BrandDemo Maven Webapp</name><url>http://maven.apache.org</url><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!--MyBatis依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.16</version></dependency><!--mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!--Servlet依赖--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope><!--依赖范围关键字provided:在编译环境和测试环境有效,但在真正运行时就不会在使用该jar包--></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><finalName>BrandDemo</finalName><plugins><!-- Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version></plugin></plugins></build> </project>
-
-
创建三层架构包结构
-
创建数据库表tb_brand并使IDEA与数据库建立连接,SQL代码如下
DROP TABLE IF EXISTS tb_brand;-- 创建品牌表brand CREATE TABLE IF NOT EXISTS 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);SELECT * FROM tb_brand;
-
创建实体类
Brand
(此为Pojo类 :存放对数据库中数据封装的对象),代码如下java">package at.guigu.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, 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;}@Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';} }
-
MyBrtis基础环境配置
-
在mapper包下创建
BrandMapper
接口 -
在项目的源代码配置文件目录(即main包下的resources目录下)创建多层目录,多层目录对应Mapper接口所在的多层包,然后再该包中创建
BrandMapper.xml
SQL映射文件,基本代码如下<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace:名称空间 --> <mapper namespace="at.guigu.mapper.BrandMapper"><!--结果映射--><resultMap id="brandResultMap" type="brand"><!--由于id为主键,且数据库中的字段名和对应结果映射的目标类中的属性名一样,所以此处不需要主键映射,只需进行非主键映射即可--><result column="brand_name" property="brandName"/><result column="company_name" property="companyName"/></resultMap></mapper>
-
在项目的源代码配置文件目录(即main包下的resources目录下)创建MyBatis核心配置文件
mybatis-config.xml
,代码如下<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!--设置别名--><typeAliases><package name="at.guigu.pojo"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--数据库 连接信息--><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><mappers><!--加载SQL映射文件:传入sql映射文件的路径--> <!-- <mapper resource="at/guigu/mapper/BrandMapper.xml"/>--><package name="at.guigu.mapper"/></mappers> </configuration>
-
查询所有
-
解释:页面上有一个“查询所有”的超链接,单击该链接即显示出查询数据,如图所示
-
要完成该问则需满足三层架构,各层需要做的工作如下所示
-
Dao层/Map层
-
Step1:
BrandMapper
接口中写入查询所有数据的方法java">package at.guigu.mapper;import at.guigu.pojo.Brand; import java.util.List;public interface BrandMapper {//查询并返回所有商品/*@Select("select * from tb_brand")@ResultMap("brandResultMap")*/List<Brand> selectAll(); }
- 注意:
- 对数据库中的字段进行结果映射后,若想要用注解方式输写SQL语句则需要另外加上注解
@ResultMap("brandResultMap")
,才能使结果映射生效(结果映射可详见MyBatis那一节) - 由于我在SQL映射文件中输入SQL语句,所以不需要改代码中的两个注解;若使用MyBatis注解开发(即SQL语句写在注解中)则需要加上以上两个注解
- 对数据库中的字段进行结果映射后,若想要用注解方式输写SQL语句则需要另外加上注解
- 注意:
-
Step2: 在对应的SQL映射文件
BrandMapper.xml
中写入SQL语句<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace:名称空间 --> <mapper namespace="at.guigu.mapper.BrandMapper"><!--结果映射--><resultMap id="brandResultMap" type="brand"><!--由于id为主键,且数据库中的字段名和对应结果映射的目标类中的属性名一样,所以此处不需要主键映射,只需进行非主键映射即可--><result column="brand_name" property="brandName"/><result column="company_name" property="companyName"/></resultMap><!--id:为sql语句的唯一标识resultType:为对应sql语句执行完毕后返回结果的类型--><select id="selectAll" resultMap="brandResultMap">select * from tb_brand;</select> </mapper>
-
-
Service层
-
由于Service层中的类均需要调用Mapper接口中的方法,那么该层中的类就都需要载核心配置文件,来获取
SqlSessionFactory
SQL连接工厂对象,所以就可以将SqlSessionFactory
封装为一个工具类。所以在完善Service
层之前需要先在util
包下将工具类SqlSessionFactoryUtils
创建好,代码如下:java">package at.guigu.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 SqlSessionFactoryUtils {private static SqlSessionFactory sqlSessionFactory;static {//静态代码快会随着类的加载而自动执行,且只执行一次try {//配置mybatis-config.xml文件路径。注意:若该文件直接在resources目录下,则直接写文件名即可String resource = "mybatis-config.xml";//利用Resources类中的静态方法将配置文件加载到内存InputStream inputStream = Resources.getResourceAsStream(resource);//获取SqlSessionFactory对象sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}public static SqlSessionFactory getSqlSessionFactory() {return sqlSessionFactory;} }
-
Step1: 在
service
包下创建BrandService
类来调用mapper
包下的BrandMapper
接口中的方法,代码如下注意:获取SqlSessionFactory对象的代码放在了成员变量的位置,这样所有方法可共用该对象,并不需要重复获取
java">package at.guigu.service;import at.guigu.mapper.BrandMapper; import at.guigu.pojo.Brand; import at.guigu.util.SqlSessionFactoryUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory;import java.io.IOException; import java.util.List;public class BrandService {//1 获取SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();public List<Brand> getAll() throws IOException {//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行sql语句List<Brand> brands = brandMapper.selectAll();sqlSession.close();return brands;} }
-
-
Web层
-
Step1:由于是通过单击页面
index.html
上查询所有
从而显示出查询数据,所以首先要创建一个index.html
页面,代码如下- 注意:html文件名默认为index时,若我们不输入资源则运行该Web项目后浏览器会默认访问到该html页面
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><a href="/BrandDemo/selectAllServlet">查询所有</a></body> </html>
-
Step2:创建
SelectAllServlet
类,且代码如下- 注意:创建一个私有的
BrandService
对象应将其放在成员变量的位置,因为对于大工程来说可能会多次用到Service
对象
java">package at.guigu.web;import at.guigu.pojo.Brand; import at.guigu.service.BrandService;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException; import java.util.List;@WebServlet("selectAllServlet") public class SelectAllServlet extends HttpServlet {//1 创建一个私有的BrandService对象private BrandService brandService = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//2 调用BrandService中的方法查询所有数据List<Brand> brands = brandService.getAll();//2 存储数据到Request域中request.setAttribute("brands", brands);//3 转发到brand.jsp中request.getRequestDispatcher("/brand.jsp").forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
- 注意:创建一个私有的
-
Step3:在Web项目核心目录下创建brand.jsp,且代码如下
jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><input type="button" value="新增"><br><hr><table border="1" cellspacing="0"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="xuhao"><tr align="center"><td>${xuhao.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:choose><c:when test="${brand.status==1}"><td>启用</td></c:when><c:otherwise><td>禁用</td></c:otherwise></c:choose><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach></table></body> </html>
-
-
三层架构都准备完毕后Tomcat启动该Web项目,Web项目启动成功后会默认运行index.html文件,然后单击
查询所有
即可跳转到另一页面显示出查询数据,如图所示
添加
-
解释
单击
新增
按钮后跳转到添加品牌的页面(该页面为addBrand.jsp
),然后输入要添加的品牌信息后单击提交,提交后浏览器将请求数据提交到服务器的Servlet,然后将数据保存到数据库中,最后重新展示一下查询所有的页面,即可显示出最新的所有数据 -
各层需要做的工作如图所示
-
Dao层/Map层
-
Step1:
BrandMapper
接口中写入添加数据的方法java">package at.guigu.mapper;import at.guigu.pojo.Brand; import at.guigu.service.BrandService; import org.apache.ibatis.annotations.ResultMap; import org.apache.ibatis.annotations.Select;import java.util.List;public interface BrandMapper {//查询并返回所有商品/*@Select("select * from tb_brand")@ResultMap("brandResultMap")*/List<Brand> selectAll();//添加商品/*@Select("insert into tb_brand values(#{brandName},#{companyName},#{ordered},#{description},#{status})")*/void add(Brand brand); }
- 注意:
- 对数据库中的字段进行结果映射后,若想要用注解方式输写 查询 的SQL语句则需要另外加上注解
@ResultMap("brandResultMap")
,才能使结果映射生效(结果映射可详见MyBatis那一节) - 由于我在SQL映射文件中输入 查询 的SQL语句,所以不需要代码中的两个注解;若使用MyBatis注解开发(即SQL语句写在注解中)则需要加上以上两个注解
- 对数据库中的字段进行结果映射后,若想要用注解方式输写 查询 的SQL语句则需要另外加上注解
- 注意:
-
Step2: 在对应的SQL映射文件
BrandMapper.xml
中写入SQL语句<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace:名称空间 --> <mapper namespace="at.guigu.mapper.BrandMapper"><!--结果映射--><resultMap id="brandResultMap" type="brand"><!--由于id为主键,且数据库中的字段名和对应结果映射的目标类中的属性名一样,所以此处不需要主键映射,只需进行非主键映射即可--><result column="brand_name" property="brandName"/><result column="company_name" property="companyName"/></resultMap><!--id:为sql语句的唯一标识resultType:为对应sql语句执行完毕后返回结果的类型--><select id="selectAll" resultMap="brandResultMap">select * from tb_brand;</select><insert id="add">insert into tb_brand values (null, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status});</insert> </mapper>
-
-
Service层
-
工具类
SqlSessionFactoryUtils
代码省略,详见查询所有中的SqlSessionFactoryUtils
代码 -
Step1: 在service包下创建BrandService类来调用mapper包下的BrandMapper接口中的方法,代码如下
java">package at.guigu.service;import at.guigu.mapper.BrandMapper; import at.guigu.pojo.Brand; import at.guigu.util.SqlSessionFactoryUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory;import java.io.IOException; import java.util.List;public class BrandService {//1 获取SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();/*** 查询所有* @return* @throws IOException*/public List<Brand> getAll() throws IOException {//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行sql语句List<Brand> brands = brandMapper.selectAll();sqlSession.close();return brands;}/*** 添加品牌* @param brand*/public void add(Brand brand){//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行添加品牌的sql语句brandMapper.add(brand);//3 注意:增删改的SQL语句需要手动提交事务让其生效sqlSession.commit();//释放资源sqlSession.close();} }
-
-
Web层
-
Step1:在Web项目核心目录下创建
addBrand.jsp
,且代码如下jsp"><%@ page contentType="text/html;charset=UTF-8" language="java" %> <html><head><title>添加品牌</title></head><body><h3>添加品牌</h3><!--action的属性值为浏览器提交到服务器的资源路径--><form action="/BrandDemo/addServlet" method="post">品牌名称:<input name="brandName"><br>企业名称:<input name="companyName"><br>排序:<input name="ordered"><br>描述信息:<testarea rows="5" cols="20" name="description"></testarea><br>状态:<input type="radio" name="status" value="0">禁用<input type="radio" name="status" value="1">禁用<br><input type="submit" value="提交"></form></body> </html>
-
Step2:通过J
avaScript
代码来为brand.jsp
中的新增
按钮添加鼠标单击事件 (可详见前端知识点汇总),单击新增
按钮后页面跳转到添加品牌的页面(即addBrand.jsp
)代码如下所示jsp"><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><input type="button" value="新增" id="add"><br><hr><table border="1" cellspacing="0"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="xuhao"><tr align="center"><td>${xuhao.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:choose><c:when test="${brand.status==1}"><td>启用</td></c:when><c:otherwise><td>禁用</td></c:otherwise></c:choose><td><a href="#">修改</a> <a href="#">删除</a></td></tr></c:forEach></table><script>document.getElementById("add").onclick = function () {//addBrand.jsp的路径location.href = "/BrandDemo/addBrand.jsp";}</script></body> </html>
-
Step3:创建
AddServlet
类,且代码如下java">package at.guigu.web;import at.guigu.pojo.Brand; import at.guigu.service.BrandService;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException;@WebServlet("/addServlet") public class AddServlet extends HttpServlet {//1 创建一个私有的BrandService对象private BrandService brandService = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//添加数据时注意要处理中文乱码问题//处理post请求乱码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 = new Brand();brand.setBrandName(brandName);brand.setCompanyName(companyName);//将字符串数字先转换为Integer类型在存入Brand中brand.setOrdered(Integer.parseInt(ordered));brand.setDescription(description);brand.setStatus(Integer.parseInt(status));//3 调用brandService完成添加brandService.add(brand);//转发到查询所有的Servletrequest.getRequestDispatcher("/selectAllServlet").forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
-
-
三层架构都准备完毕后Tomcat启动该Web项目,Web项目启动成功后会默认运行
index.html
文件,然后单击查询所有
即可跳转到另一页面显示出查询数据,之后单击新增
按钮,填写完新增数据后单击提交按钮,数据被提交到数据库保存,然后页面会自动跳转到查询所有的页面,显示出所有品牌数据,如图所示
修改——回显数据
-
解释
单击对应品牌的
修改
按钮后,会跳转到新的页面(该页面为update.jsp
),该页面会显示你要修改的品牌上次所保存的内容 -
各层需要做的工作如图所示
-
Dao层/Map层
-
Step1:
BrandMapper
接口中写入修改数据的方法java">package at.guigu.mapper;import at.guigu.pojo.Brand; import at.guigu.service.BrandService; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.ResultMap; import org.apache.ibatis.annotations.Select;import java.util.List;public interface BrandMapper {/*@Select("select * from tb_brand")@ResultMap("brandResultMap")*/List<Brand> selectAll();//@Insert("insert into tb_brand values (null, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status})")void add(Brand brand);//修改——回显数据void selectById(int id); }
-
Step2: 在对应的SQL映射文件
BrandMapper.xml
中写入SQL语句<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace:名称空间 --> <mapper namespace="at.guigu.mapper.BrandMapper"><!--结果映射--><resultMap id="brandResultMap" type="brand"><!--由于id为主键,且数据库中的字段名和对应结果映射的目标类中的属性名一样,所以此处不需要主键映射,只需进行非主键映射即可--><result column="brand_name" property="brandName"/><result column="company_name" property="companyName"/></resultMap><!--id:为sql语句的唯一标识resultType:为对应sql语句执行完毕后返回结果的类型--><!--查询所有品牌--><select id="selectAll" resultMap="brandResultMap">select * from tb_brand;</select><!--添加品牌--><insert id="add">insert into tb_brand values (null, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status});</insert><!--修改——回显数据:根据id查询--><select id="selectById" resultMap="brandResultMap">select * from tb_brand where id = #{id};</select> </mapper>
-
-
Service层
-
工具类
SqlSessionFactoryUtils
代码省略,详见查询所有中的SqlSessionFactoryUtils
代码 -
Step1: 在service包下创建BrandService类来调用mapper包下的BrandMapper接口中的方法,代码如下
java">package at.guigu.service;import at.guigu.mapper.BrandMapper; import at.guigu.pojo.Brand; import at.guigu.util.SqlSessionFactoryUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory;import java.io.IOException; import java.util.List;public class BrandService {//1 获取SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();/*** 查询所有* @return* @throws IOException*/public List<Brand> getAll() throws IOException {//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行sql语句List<Brand> brands = brandMapper.selectAll();sqlSession.close();return brands;}/*** 添加品牌* @param brand*/public void add(Brand brand){//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行添加品牌的sql语句brandMapper.add(brand);//3 注意:增删改的SQL语句需要手动提交事务让其生效sqlSession.commit();//释放资源sqlSession.close();}/*** 修改——回显数据:根据id查询* @param id* @return* @throws IOException*/public Brand selectById(int id) throws IOException {//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行修改——回显数据的sql语句Brand brand = brandMapper.selectById(id);//释放资源sqlSession.close();return brand;} }
-
-
Web层
-
Step1:在Web项目核心目录下创建
update.jsp
,且代码如下jsp"><%--Created by IntelliJ IDEA.User: 10195Date: 2024/6/30Time: 16:49To change this template use File | Settings | File Templates. --%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>修改品牌</title></head><body><h3>修改品牌</h3><!--action的属性值为浏览器提交到服务器的资源路径--><form action="/BrandDemo/addServlet" 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:choose><c:when test="${brand.status == 0}"><input type="radio" name="status" value="0" checked>禁用<input type="radio" name="status" value="1">启用<br></c:when><c:otherwise><input type="radio" name="status" value="0">禁用<input type="radio" name="status" value="1" checked>启用<br></c:otherwise></c:choose><input type="submit" value="提交"></form></body> </html>
-
Step2:通过J
avaScript
代码来为brand.jsp
中的修改
按钮添加鼠标单击事件 (可详见前端知识点汇总),单击修改
按钮后页面会根据id
跳转到对应品牌的页面(即.jsp
),代码如下所示jsp"><%--Created by IntelliJ IDEA.User: 10195Date: 2024/6/28Time: 19:40To change this template use File | Settings | File Templates. --%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>Title</title></head><body><input type="button" value="新增" id="add"><br><hr><table border="1" cellspacing="0"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="xuhao"><tr align="center"><td>${xuhao.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:choose><c:when test="${brand.status==1}"><td>启用</td></c:when><c:otherwise><td>禁用</td></c:otherwise></c:choose><td><a href="/BrandDemo/selectByIdServlet?id=${brand.id}">修改</a> <a href="#">删除</a></td></tr></c:forEach></table><script>document.getElementById("add").onclick = function () {//addBrand.jsp的路径location.href = "/BrandDemo/addBrand.jsp";}</script></body> </html>
-
Step3:创建
SelectByIdServlet
类,且代码如下java">package at.guigu.web;import at.guigu.pojo.Brand; import at.guigu.service.BrandService;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException;@WebServlet("/selectByIdServlet") public class SelectByIdServlet extends HttpServlet {//1 创建一个私有的BrandService对象private BrandService brandService = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//2 接收idString id = request.getParameter("id");//3 调用对应的Service查询Brand brand = brandService.selectById(Integer.parseInt(id));//4 将该Brand对象存储到request域中request.setAttribute("brand", brand);//5 转发到update.jsp中request.getRequestDispatcher("/update.jsp").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
-
-
三层架构都准备完毕后Tomcat启动该Web项目,Web项目启动成功后会默认运行
index.html
文件,然后单击查询所有
即可跳转到另一页面显示出查询数据,之后单击修改
按钮后会自动跳转到修改品牌页面,如图所示
修改——修改数据
-
解释:修改数据是在回显数据的基础上进行操作的,即对
update.jsp
页面的表单进行修改后单击提交
按钮,将数据保存到数据库中,最后重现展示一下查询所有的页面,即可显示出最新的所有数据 -
各层需要做的工作如图所示
-
Dao层/Map层
-
Step1:
BrandMapper
接口中写入修改数据的方法java">package at.guigu.mapper;import at.guigu.pojo.Brand; import at.guigu.service.BrandService; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.ResultMap; import org.apache.ibatis.annotations.Select;import java.util.List;public interface BrandMapper {/*@Select("select * from tb_brand")@ResultMap("brandResultMap")*/List<Brand> selectAll();//@Insert("insert into tb_brand values (null, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status})")void add(Brand brand);/*** //修改——回显数据:根据id查询* @param id* @return*//*@Select("select * from tb_brand where id = #{id}")@ResultMap("brandResultMap")*/Brand selectById(int id);//修改——修改数据void update(Brand brand); }
-
Step2: 在对应的SQL映射文件
BrandMapper.xml
中写入SQL语句<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace:名称空间 --> <mapper namespace="at.guigu.mapper.BrandMapper"><!--结果映射--><resultMap id="brandResultMap" type="brand"><!--由于id为主键,且数据库中的字段名和对应结果映射的目标类中的属性名一样,所以此处不需要主键映射,只需进行非主键映射即可--><result column="brand_name" property="brandName"/><result column="company_name" property="companyName"/></resultMap><!--id:为sql语句的唯一标识resultType:为对应sql语句执行完毕后返回结果的类型--><!--查询所有品牌--><select id="selectAll" resultMap="brandResultMap">select * from tb_brand;</select><!--添加品牌--><insert id="add">insert into tb_brand values (null, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status});</insert><!--修改——回显数据:根据id查询--><select id="selectById" resultMap="brandResultMap">select * from tb_brand where id = #{id};</select><!--修改——修改数据--><update id="update">update tb_brandset brand_name=#{brandName},company_name=#{companyName},ordered=#{ordered},description=#{description},status=#{status}where id=#{id};</update> </mapper>
-
-
Service层
-
工具类
SqlSessionFactoryUtils
代码省略,详见查询所有中的SqlSessionFactoryUtils
代码 -
Step1: 在service包下创建BrandService类来调用mapper包下的BrandMapper接口中的方法,代码如下
java">package at.guigu.service;import at.guigu.mapper.BrandMapper; import at.guigu.pojo.Brand; import at.guigu.util.SqlSessionFactoryUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory;import java.io.IOException; import java.util.List;public class BrandService {//1 获取SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();/*** 查询所有* @return* @throws IOException*/public List<Brand> getAll() throws IOException {//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行sql语句List<Brand> brands = brandMapper.selectAll();sqlSession.close();return brands;}/*** 添加品牌* @param brand*/public void add(Brand brand){//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行添加品牌的sql语句brandMapper.add(brand);//3 注意:增删改的SQL语句需要手动提交事务让其生效sqlSession.commit();//释放资源sqlSession.close();}/*** 修改——回显数据:根据id查询* @param id* @return*/public Brand selectById(int id){//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行修改——回显数据的sql语句Brand brand = brandMapper.selectById(id);//释放资源sqlSession.close();return brand;}/*** 修改——修改数据* @param brand*/public void update(Brand brand) {//2 获取SqlSession对象,执行SQL语句//2.1 获取SqlSession对象SqlSession sqlSession = sqlSessionFactory.openSession();//2.2 获取Mapper接口UserMapper的代理对象BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);//2.3 执行修改——修改数据的sql语句brandMapper.update(brand);//3 注意:增删改的SQL语句需要手动提交事务让其生效sqlSession.commit();//释放资源sqlSession.close();} }
-
-
Web层
-
Step1:修改在回显数据内容中的
update.jsp
,代码如下- 注意:由于是通过id进行品牌数据的修改,所以需要将id提交到服务端
jsp"><%--Created by IntelliJ IDEA.User: 10195Date: 2024/6/30Time: 16:49To change this template use File | Settings | File Templates. --%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html><head><title>修改品牌</title></head><body><h3>修改品牌</h3><!--action的属性值为浏览器提交到服务器的资源路径--><form action="/BrandDemo/updateServlet" method="post"><%--通过隐藏域提交id,作用:隐藏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:choose><c:when test="${brand.status == 0}"><input type="radio" name="status" value="0" checked>禁用<input type="radio" name="status" value="1">启用<br></c:when><c:otherwise><input type="radio" name="status" value="0">禁用<input type="radio" name="status" value="1" checked>启用<br></c:otherwise></c:choose><input type="submit" value="提交"></form></body> </html>
-
Step2:通过J
avaScript
代码来为brand.jsp
中的修改
按钮添加鼠标单击事件 (可详见前端知识点汇总),单击修改
按钮后页面会根据id
跳转到对应品牌的页面(即.jsp
),代码详见回显数据部分内容 -
Step3:创建
UpdateServlet
类,且代码如下java">package at.guigu.web;import at.guigu.pojo.Brand; import at.guigu.service.BrandService;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; import java.io.IOException;@WebServlet("/updateServlet") public class UpdateServlet extends HttpServlet {//1 创建一个私有的BrandService对象private BrandService brandService = new BrandService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//添加数据时注意要处理中文乱码问题//处理post请求乱码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 = new Brand();brand.setId(Integer.parseInt(id));brand.setBrandName(brandName);brand.setCompanyName(companyName);//将字符串数字先转换为Integer类型在存入Brand中brand.setOrdered(Integer.parseInt(ordered));brand.setDescription(description);brand.setStatus(Integer.parseInt(status));//3 调用brandService完成修改brandService.update(brand);//转发到查询所有的Servletrequest.getRequestDispatcher("/selectAllServlet").forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);} }
-
-
三层架构都准备完毕后Tomcat启动该Web项目,Web项目启动成功后会默认运行
index.html
文件,然后单击查询所有
即可跳转到另一页面显示出查询数据,之后单击修改
按钮后会自动跳转到修改品牌页面,修改完数据后单击提交
按钮,数据被提交到数据库保存,然后页面会自动跳转到查询所有的页面,显示出所有品牌数据,如图所示