MVC案例之通过配置切换底层存储源(面向接口)
1.深入理解面向接口编程:
在类中调用接口的方法,而不必关心具体的实现。这将有利于代码的解耦。使程序有更好的可移植性
和可扩展性

动态修改 Customer 的存储方式:通过修改类路径下的 switch.properties 文件的方式来实现
switch.properties

①. CustomerServlet 中不能在通过 private CustomerDAO customerDAO =
new CustomerDAOXMLImpl(); 的方式来写死实现类
②. 需要通过一个类的一个方法来获取具体的实现类的对象
2.实现步骤
①
当前 WEB 应用才启动的时候,InitServlet 被创建,并由 Servlet 容器调用其 init() 方法:
读取类路径下的 switch.properties 文件
获取 switch.properties 的 type 属性值
赋给了 CustomerDAOFactory 的 type 属性值
InitServlet
package com.aff.mvcapp.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import com.aff.mvcapp.dao.factory.CustomerDAOFactory; @WebServlet("/initServlet")
public class InitServlet extends HttpServlet {
private static final long serialVersionUID = 1L; @Override
public void init() throws ServletException {
CustomerDAOFactory.getInstance().setType("jdbc");
InputStream is = getServletContext().getResourceAsStream("/WEB-INF/classes/switch.properties");
Properties properties = new Properties();
try {
properties.load(is);
String type = properties.getProperty("type");
CustomerDAOFactory.getInstance().setType(type);
} catch (IOException e) {
e.printStackTrace();
}
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<servlet>
<servlet-name>CustomerServlet</servlet-name>
<servlet-class>com.aff.mvcapp.servlet.CustomerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CustomerServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping> <servlet>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.aff.mvcapp.servlet.InitServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
②
创建 CustomerServlet 时,为 customerDAO 属性赋值是通过 CustomerDAOFactory 的
getCustomerDAO() 方法完成的 。
此时的 type 已经在 InitServlet 中被赋值了。
CustomerServlet
package com.aff.mvcapp.servlet;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
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 com.aff.mvcapp.dao.CriteriaCustomer;
import com.aff.mvcapp.dao.CustomerDAO;
import com.aff.mvcapp.dao.factory.CustomerDAOFactory;
import com.aff.mvcapp.domian.Customer; @WebServlet("/customerServlet")
public class CustomerServlet extends HttpServlet {
private CustomerDAO customerDAO = CustomerDAOFactory.getInstance().getCustomerDAO();
//private CustomerDAO customerDAO = new CustomerDAOImpl(); private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
} protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 获取ServletPath: /edit.do 或 addCustomer.do
String servletPath = request.getServletPath();
// 2.去除 / 和 .do 得到类似于 edit 或 addCustomer 这样的字符串
String methodName = servletPath.substring(1);
methodName = methodName.substring(0, methodName.length() - 3); try {
// 3.利用反射获取 methodName 对应的方法
Method method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class,
HttpServletResponse.class);
// 4.利用反射调用对应的方法
method.invoke(this, request, response);
} catch (Exception e) {
// e.printStackTrace();
// 可以有一些响应
response.sendRedirect("error.jsp");
}
} private void addCustomer(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.获取表单参数:name address phone
String name = request.getParameter("name");
String address = request.getParameter("address");
String phone = request.getParameter("phone"); // 2.检验 name 是否被占用
// 2.1调用CustomerDAO的getCountWithName(String name) 获取 name 在数据库中是否存在
long count = customerDAO.getCountWithName(name);
// 2.2若返回值大于0,则响应 newcustomer.jsp 页面, 通过转发的方式响应newcustomer.jsp
if (count > 0) {
// 2.2.1要求页面显示一个错误消息: 用户名 name已经被占用,请重新选择,
// 在request中放入一个属性message :用户名 name 已经被占用,请重新选择!
// 在页面通过request.getAttribute("message")的方式显示
request.setAttribute("message", "用户名 " + name + "已经被占用,请重新选择"); // 2.2.2 newcustomer.jsp 的表单可以回显
// 通过value="<%=request.getParameter("name") == null ? "" :
// request.getParameter("name") %>"进行回显 // 2.2.3结束方法:return
request.getRequestDispatcher("/newcustomer.jsp").forward(request, response);
return;
}
// 3.若验证通过,把表单参数封装为一个Customer 对象 customer
Customer customer = new Customer(name, address, phone); // 4.调用CustomerDAO的 save(Customer customer) 执行保存操作
customerDAO.save(customer); // 5.重定向的 success.jsp 页面:使用重定向可以避免表单的重复提交问题
response.sendRedirect("success.jsp"); } private void edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String forwardPath = "/error.jsp";// 初始值
// 1.获取请求参数 id
String idStr = request.getParameter("id");
// 2.调用CustomerDAO 的 customerDAO.get(id) 获取 id 对应的Customer 对象customer
try {
Customer customer = customerDAO.get(Integer.parseInt(idStr));
if (customer != null) {// 当customer为null是转到 error.jsp
forwardPath = "/updatecustomer.jsp";
// 3.将customer放入request 中
request.setAttribute("customer", customer);
}
} catch (Exception e) {
}
// 4.响应updatecustomer.jsp 页面: 转发
request.getRequestDispatcher(forwardPath).forward(request, response); } private void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取表单参数:id,name,addres, phone, oldName
String id = request.getParameter("id");
String name = request.getParameter("name");
String address = request.getParameter("address");
String phone = request.getParameter("phone");
String oldName = request.getParameter("oldName"); // 2.检查name是否被占用
// 2.比较name和oldName 是否相同,若相同说明 name可用
// 2.1若不相同, 则调用CustomerDAO 的 getCountWithName(String name) 获取 name在数据库中是否存在
if (!oldName.equalsIgnoreCase(name)) {
long count = customerDAO.getCountWithName(name);
if (count > 0) {
// 2.2若返回值大于0,则响应 updatecustomer.jsp 页面,
// 通过转发的方式响应updatecustomer.jsp
// 2.2.1要求页面显示一个错误消息: 用户名 name已经被占用,请重新选择,
// 在request中放入一个属性message :用户名 name 已经被占用,请重新选择!
// 在页面通过request.getAttribute("message")的方式显示
request.setAttribute("message", "用户名" + name + "已经被占用,请重新选择!"); // 2.2.2 updatecustomer.jsp 的表单可以回显
// address, phone 显示提交表单的新的值,而 name 显示oldName, 而不是新提交的 name // 2.2.3结束方法:return
request.getRequestDispatcher("/updatecustomer.jsp").forward(request, response);
return;
}
} //3.若验证通过,则把表单参数封装为一个Customer 对象 customer
Customer customer = new Customer(name, address, phone);
customer.setId(Integer.parseInt(id));//表单过来的 安全的 //4.调用CustomerDAO 的 update(Customer customer) 执行更新操作
customerDAO.update(customer);
//5.重定向到 query.do
response.sendRedirect("query.do"); } private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name");
String address = request.getParameter("address");
String phone = request.getParameter("phone"); CriteriaCustomer cc = new CriteriaCustomer(name, address, phone); // 1.调用 CustomerDAO 的 getForListWithCriteriaCustomer() 得到 Customer 的集合
List<Customer> customers = customerDAO.getForListWithCriteriaCustomer(cc); // 2.把 Customer 的集合放入 request 中
request.setAttribute("customers", customers); // 3.转发页面到 index.jsp 中( 不能使用重定向)
request.getRequestDispatcher("/index.jsp").forward(request, response); } private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String idstr = request.getParameter("id");
int id = 0;
// try-catch的作用 , 防止恶意的输入, idStr 不能转为int类型,若出异常 id直接为0
try {
id = Integer.parseInt(idstr);
customerDAO.delete(id);
} catch (Exception e) {
}
response.sendRedirect("query.do");
}
}
③
CustomerDAOFactory 的 getCustomerDAO() 方法为 customerDAO 属性赋值
CustomerDAOFactory
package com.aff.mvcapp.dao.factory;
import java.util.HashMap;
import java.util.Map;
import com.aff.mvcapp.dao.CustomerDAO;
import com.aff.mvcapp.dao.impl.CustomerDAOImpl;
import com.aff.mvcapp.dao.impl.CustomerDAOXMLImpl; public class CustomerDAOFactory { private Map<String, CustomerDAO> daos = new HashMap<>();
private static CustomerDAOFactory instance = new CustomerDAOFactory();
public static CustomerDAOFactory getInstance() {
return instance;
}
public String type = null;
public void setType(String type) {
this.type = type;
}
private CustomerDAOFactory() {
daos.put("jdbc", new CustomerDAOImpl());
daos.put("xml", new CustomerDAOXMLImpl());
} public CustomerDAO getCustomerDAO() {
return daos.get(type);
} }
MVC案例之通过配置切换底层存储源(面向接口)的更多相关文章
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(3)-面向接口的编程
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(3)-面向接口的编程 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1)框架搭建 (2):数据 ...
- JavaWeb(五):MVC案例
MVC是Model-View-Controller的简称,即模型-视图-控制器.MVC是一种设计模式,它把应用程序分成三个核心模块:模型.视图.控制器,它们各自处理自己的任务.模型是应用程序的主体部分 ...
- 【JavaWeb】MVC案例之新闻列表
MVC案例之新闻列表 作者:白宁超 2016年6月6日15:26:30 摘要:本文主要针对javaweb基本开发之MVC案例的简单操作,里面涉及mysql数据库及表的创建,以及jsp页面和servle ...
- SpringBoot系列之三_一个完整的MVC案例
这一节让我们来做一个完整的案例. 我们将使用MyBatis作为ORM框架,并以非常简单的方式来使用MyBatis,完成一个完整的MVC案例. 此案例承接上一节,请先搭建好上一节案例. 一.数据库准备 ...
- Apache Druid 底层存储设计(列存储与全文检索)
导读:首先你将通过这篇文章了解到 Apache Druid 底层的数据存储方式.其次将知道为什么 Apache Druid 兼具数据仓库,全文检索和时间序列的特点.最后将学习到一种优雅的底层数据文件结 ...
- Kooboo CMS技术文档之三:切换数据存储方式
切换数据存储方式包括以下几种: 将文本内容存储在SqlServer.MySQL.MongoDB等数据库中 将站点配置信息存储在数据库中 将后台用户信息存储在数据库中 将会员信息存储在数据库中 将图片. ...
- Percona 开始尝试基于Ceph做上层感知的分布式 MySQL 集群,使用 Ceph 提供的快照,备份和 HA 功能来解决分布式数据库的底层存储问题
本文由 Ceph 中国社区 -QiYu 翻译 英文出处:Using Ceph with MySQL 欢迎加入CCTG Over the last year, the Ceph world drew m ...
- ASP.NET MVC案例教程(二)
ASP.NET MVC案例教程(二) 让第一个页面跑起来 现在,我们来实现公告系统中的第一个页面——首页.它非常简单,只包括所有公告分类的列表,并且每个列表项是一个超链接.其中分类数据是用我们的Moc ...
- ASP.NET MVC案例教程(三)
ASP.NET MVC案例教程(二) 让第一个页面跑起来 现在,我们来实现公告系统中的第一个页面——首页.它非常简单,只包括所有公告分类的列表,并且每个列表项是一个超链接.其中分类数据是用我们的Moc ...
随机推荐
- Spring Boot入门系列(十三)如何实现事务
前面介绍了Spring Boot 中的整合Mybatis并实现增删改查.不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1 ...
- Spring源码阅读 之 配置的读取,解析
在上文中我们已经知道了Spring如何从我们给定的位置加载到配置文件,并将文件包装成一个Resource对象.这篇文章我们将要探讨的就是,如何从这个Resouce对象中加载到我们的容器?加载到容器后又 ...
- webpack-常用配置知识点
webpack配置多页面 webpcak配置多页面需要在entry中配置多个,在plugins中配置多个htmlWebpackPlugin,具体如下 entry:{ "index" ...
- 13_JavaScript基础入门(3)
条件分支语句 条件分支语句,也叫作条件判断语句,就是根据某种条件执行某些语句,不执行某些语句. JS中有三种语法是可以表示条件分支的. 1.if--else-- 条件分支的主力语法,这个主力语法能够书 ...
- .Net Core微服务化ABP之六——处理Authentication
上篇中我们已经可以实现sso,并且为各个服务集成sso认证.本篇处理权限系统的角色问题,权限系统分两层,第一层为整体系统角色权限,区分app用户.后台用户.网站用户的接口权限,第二层为业务系统权限,对 ...
- [hdu1317]spfa
题意:给一个有向图,每个点有一个权值,从1个点出发,初始能量有100,每到达新的点,能量就会加上那个点的权值,当能量大于0时才能继续走,可以多次进入同一点.问能否到达目标点 思路:如果没正权环,则直接 ...
- yum安装mysql 之后问题
日志报错: 190412 15:56:50 [ERROR] Can't open the mysql.plugin table. Please run mysql_upgrade to create ...
- buuctf-pwn刷题-axb_2019_heap
版权声明:本文为CSDN博主「L.o.W」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/weixin_441 ...
- 基于hexo创建博客(Github托管)
基于hexo的博客 搭建好的博客网站 dengshuo7412.com 搭建步骤 1.依赖文件下载 Node.js 2.Hexo的安装 3.部署到Github 4.Hexo创建博客基本操作 5.Hex ...
- vue v-for 渲染input 输入有问题 解决方案
v-for循环input标签的时候输入信息两个输入框一同显示输入信息 解决方案: <input :placeholder="items.title" v-model = &q ...