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 ...
随机推荐
- Nginx模块开发(3)————使用upstream访问第三方服务
该模块可以完成如下的功能,当我们输入http://你的ip/lcwupstream时,会使用upstream方式访问淘宝搜索,打开淘宝搜索的主页面,代码如下: //start from the ver ...
- zabbix tigger 设置
设置一个内存在10分钟内持续低于某值才告警: 设置方法: 修改模板的tigger configuration - > Template OS linux Active(选择自己的模板)-&g ...
- python-unittest环境下单独运行一个用例的方法
在unittest单元测试的框架下,想要调出如图所示的绿三角 需要有两个步骤: 1.确定在工具栏中时在unittest模式下运行的,如果为普通模式的话可以通过下三角下拉修改运行环境: 2.在代码中im ...
- React 导入组件前段浏览器报错 “Cannot read property 'Component' of undefined”
问题出在这个花括号上,当你写{React}的时候,他只会导入React,并不会导入下面你要用到的Component组件, 所以,将括号去掉就可以了. 别忘记保存.
- uniapp自定义简单省市区联动组件
又双叒一个uniapp组件 最近有一个选择地址的需求,就写了一个省市区联动选择器. 选择日期使用的picker,就照着它简单的整了一个,使用网络请求城市数据,还用到了vuex组件数据共享. 本来自己整 ...
- OpenWrt(LEDE)2020.4.12编译 UnPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成
固件说明 基于Lede OpenWrt R2020.4.8版本(源码截止2020.4.12)Lienol Feed及若干自行维护的软件包 结合家庭x86软路由场景需要定制 按照家庭应用场景对固件及软件 ...
- Spring Cloud 系列之 Config 配置中心(一)
服务配置现状 配置文件是我们再熟悉不过的,在微服务系统中,每个微服务不仅仅只有代码,还需要连接其他资源,例如数据库的配置或功能性的开关 MySQL.Redis .Security 等相关的配置.除了项 ...
- 风扇转速通过FPGA采样
1.风扇最大转速16000RPM,那么每一转需要时间60S/16000=0.00375S=375*10^4ns=T=T1+T2+T3+T4: 2.采样0.6S内的风扇detect信号的上升沿个数:0. ...
- 设计模式之GOF23原型模式01
原型模式prototype 原型模式: - 通过new产生一个对象需要非常繁琐的数据准备或者访问权限,则可以使用原型模式,比如如果new对象所需时间过长,可以通过克隆产生相同的副本 - Java中的克 ...
- 如何应对Kubernetes的安全挑战?
导读:Kubernetes的广泛使用证明了企业的信念,即他们不仅具有处理现代应用程序开发和现代化计划的复杂性的能力,而且具有大规模处理能力. 根据CNCF对各种规模的公司中1340位技术专家的最新调查 ...