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,引入坐标
<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>
创建三层架构的包结构
作用:
web:web相关的包
service:服务器
mapper:存放mybatis接口的
pojo:放实体类
util:放工具类
数据库表 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);
SELECT * FROM tb_brand;
实体类 Brand
package com.zcl.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 +
'}';
}
}
MyBatis 基础环境
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.zcl.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.zcl.mapper"/>
mappers>
configuration>
根据自己的环境修改包名和连接配置
包扫描pojo按住ctrl+左键点击鼠标变成小手就是正确了
BrandMapper.xml
在resources文件下创建包结构
com/zcl/mapper
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zcl.mapper.BrandMapper">
<resultMap id="brandResultMap" type="brand">
<result column="brand_name" property="brandName">result>
<result column="company_name" property="companyName">result>
resultMap>
mapper>
namespace报错,创建BrandMapper接口解决
BrandMapper接口
com.zcl.mapper
目录下
package com.zcl.mapper;
/**
* TODO:
*
* @author zcl
* @date 2022/3/27 22:00
*/
public interface BrandMapper {
}
当我们点击 index.html
页面中的 查询所有
这个超链接时,就能查询到上图右半部分的数据。
对于上述的功能,点击 查询所有
超链接是需要先请后端的 servlet
,由 servlet
跳转到对应的页面进行数据的动态展示。而整个流程如下图:
在 mapper
包下创建创建 BrandMapper
接口,在接口中定义 selectAll()
方法
/**
* 查询所有
* @return
*/
@Select("select * from tb_brand")
@ResultMap("brandResultMap")
List<Brand> selectAll();
util
包下的:SqlSessionFactoryUtils
package com.zcl.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 {
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;
}
}
package com.zcl.service;
import com.zcl.mapper.BrandMapper;
import com.zcl.pojo.Brand;
import com.zcl.util.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;
/**
* TODO:
*
* @author zcl
* @date 2022/3/27 22:14
*/
public class BrandService {
// 调用SqlSessionFactoryUtils根据类里面的方法【所有成员都会访问】
SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();
/**
* 查询所有功能
* @return
*/
public List<Brand> selectAll(){
// 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 调用具体的方法
List<Brand> brandList = mapper.selectAll();
// 释放资源
sqlSession.close();
return brandList;
}
}
【Web层】
启动执行流程:启动项目默认访问index.html页面,点击a标签跳转到SelectAllServlet控制器,获取所有数据储存到域中再请求转发到brand2.jsp中遍历数据输出
创建index.html页面
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<a href="/brand_demo/selectAllServlet">查询所有a>
body>
html>
web
包下创建SelectAllServlet
数据库查询的数据储存到域在中
请求转发路径
package com.zcl.web; /**
* TODO:
*
* @author zcl
* @date 2022/3/28 7:04
*/
import com.zcl.pojo.Brand;
import com.zcl.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 {
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("/brand2.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
创建brand.jsp页面
获取域中的数据并使用jstl标签遍历生成表格
<%@ 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}
启用
禁用
修改 删除
启动项目
默认到index页面
点击查询所有遍历数据
项目文件结构顺序
上图是做 添加 功能流程。点击 新增
按钮后,会先跳转到 addBrand.jsp
新增页面,在该页面输入要添加的数据,输入完毕后点击 提交
按钮,需要将数据提交到后端,而后端进行数据添加操作,并重新将所有的数据查询出来。整个流程如下:
【dao层】
在 BrandService
类中定义添加品牌数据方法 add(Brand brand)
/**
* 添加数据
* @param brand
*/
@Insert("insert into tb_brand values (null,#{brandName},#{companyName},#{ordered},#{description},#{status})")
void add(Brand brand);
【service层】
在service包下的BrandService类中添加
增删改方法都需要提交事务,再释放资源
/**
* 添加数据
* @param brand
*/
public void add(Brand brand){
// 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 调用具体的方法
mapper.add(brand);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
【Web层】
在brand.jsp页面的新增按钮添加点击事件跳转到新增的页面
<script>
document.getElementById("add").onclick = function (){
location.href = "/brand-demo2/addBrand.jsp";
}
</script>
创建addBrand.html页面
设置action路径在通过控制器请求转发到查询页面
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加品牌title>
head>
<body>
<h3>添加品牌h3>
<form action="/brand-demo2/addServicelet" 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>
在web包下创建AddServlet控制器
需要处理post请求乱码问题
// 处理post请求乱码问题 request.setCharacterEncoding("utf-8");
package com.zcl.web; /**
* TODO:
*
* @author zcl
* @date 2022/3/28 10:10
*/
import com.zcl.pojo.Brand;
import com.zcl.service.BrandService;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
// 创建BrandService对象调用方法
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 处理post请求乱码问题
request.setCharacterEncoding("utf-8");
// 1、接收表单数据
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");
// 2、封装为一个Brand对象
Brand brand = new Brand();
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(Integer.parseInt(ordered));
brand.setDescription(description);
brand.setStatus(Integer.parseInt(status));
// 3、调用add添加方法
service.add(brand);
// 4、转发到查询所有的jsp页面
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
查询数据,将数据存储到域对象中跳转到 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){
// 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 调用具体的方法
Brand brandList = mapper.selectById(id);
// 释放资源
sqlSession.close();
return brandList;
}
改造修改页面,点击修改跳转查询数据回填
修改 删除
创建SelectByIdServlet根据id查询信息控制器,并请求转发到修改页面
package com.zcl.web; /**
* TODO:
*
* @author zcl
* @date 2022/3/28 7:04
*/
import com.zcl.pojo.Brand;
import com.zcl.service.BrandService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/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、调用Servlet根据id查询数据
Brand brand = service.selectById(Integer.parseInt(id));
// 3、数据储存到request域中
request.setAttribute("brand",brand);
// 4、请求转发到修改回填页面
request.getRequestDispatcher("/update.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
创建修改页面update.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
修改品牌
修改品牌
启动项目效果展示
在修改页面进行数据修改,点击 提交
按钮,会将数据提交到后端程序,后端程序会对表中的数据进行修改操作,然后重新进行数据的查询操作。整体流程如下:
BrandMapper接口
/**
* 修改
* @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){
// 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 调用具体的方法
mapper.update(brand);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
<form action="/brand-demo2/updateServlet" method="post">
<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>
web包下
package com.zcl.web; /**
* TODO:
*
* @author zcl
* @date 2022/3/28 10:10
*/
import com.zcl.pojo.Brand;
import com.zcl.service.BrandService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/updateServlet")
public class UpdateServlet extends HttpServlet {
// 创建BrandService对象调用方法
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 处理post请求乱码问题
request.setCharacterEncoding("utf-8");
// 1、接收表单数据
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");
// 2、封装为一个Brand对象
Brand brand = new Brand();
brand.setId(Integer.parseInt(id));
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(Integer.parseInt(ordered));
brand.setDescription(description);
brand.setStatus(Integer.parseInt(status));
// 3、调用修改方法
service.update(brand);
// 4、转发到查询所有的jsp页面
request.getRequestDispatcher("/selectAllServlet").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
6.1、在
BrandService
类中定义根据id查询数据方法selectById(int id)
【Dao层】
/**
* 删除
* @param id
*/
@Update("delete from tb_brand where id = #{id}")
void deldate(int id);
6.2、在service包下调用方法【service层】
/**
* 根据id删除信息
* @return
*/
public void deldate(int id){
// 获取SqlSession
SqlSession sqlSession = factory.openSession();
// 获取BrandMapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 调用具体的方法
mapper.deldate(id);
// 提交事务
sqlSession.commit();
// 释放资源
sqlSession.close();
}
6.3、【Web层】
修改brand2.jsp页面的删除标签
修改 删除
创建DelServlet删除控制器
@WebServlet("/delByIdServlet")
public class DelServlet extends HttpServlet {
// 创建BrandService对象调用方法
private BrandService service = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、接收表单数据
String id = request.getParameter("id");
// 3、调用修改方法
service.deldate(Integer.parseInt(id));
// 4、转发到查询所有的jsp页面
request.getRequestDispatcher("/selectAllServlet").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}