4.1 MVC模型
MVC:Model(模型),View(视图),Controller(控制器)
视图层:用于做数据的展示以及和用户交互的一个界面=>jsp
控制层:能够接受客户端的请求并且进行请求转发,具体的业务功能还是需要借助模型层组件来完成。CoreServlet => DispacherServlet + EmpController
模型层:模型分为很多种:
1) 存值的值对象: POJO/VO(value object)/entity/bean -> Emp
2) 有数据访问对象:DAO---数据访问对象:xxxDao
3) 有业务模型对象:BO,业务对象 比如:xxxService
4) 数据传输对象:DTO data transfer object
DAO中的方法都是单精度方法 或者称之为细粒度方法。
什么叫单精度?一个方法只考虑一个操作,比如,添加,那就是insert操作。查询那就是select操作。
BO中的方法属于业务方法,但实际的业务是比较复杂的,因此业务方法的粒度是比较粗的
比如:注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
那么在这个业务方法中包含了多少个DAO方法呢,也就是说注册这个业务功能需要通过调用多个DAO方法的组合调用才能完成注册功能。
1、检查用户名是否已经被注册—DAO中的select操作。
2、向用户表新增一条新用户记录—DAO的insert操作。
3、向用户积分表新增一条记录(新用户默认初始化积分假如是100分)--DAO中的insert操作
4、向系统消息表新增一条记录(某某新用户注册了,需要根据通讯录信息向他的联系人推送消息)--DAO中的insert操作。
5、向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒注册)--DAO中的insert操作。






|
package com.hy.controller;
import com.hy.service.IEmpService; import com.hy.service.impl.EmpServiceImpl;
public class EmpController { private IEmpService empService = new EmpServiceImpl();
public void add(String ename,String pwd) { try { boolean flag = empService.reg(ename, pwd); } catch (Exception e) { e.printStackTrace(); } }
public String index() { System.out.println("EmpController...index"); return "forward:/WEB-INF/emp/index.jsp"; }
public String login(String ename,String pwd) { System.out.printf("EmpController的login方法获取的参数值ename=%s,pwd=%s",ename,pwd); return "redirect:emp.do?ac=index"; }
public String delete(Integer eid) { if(eid !=null ) { System.out.println("EmpController eid=="+eid); //empDao.delete(eid); return "forward:xxx"; } return "forward:error.xxx"; } } |
耦合/依赖 :依赖指的是谁离不开谁,这叫依赖。比如:你离不开你女朋友。你依赖你女朋友
在我们系统当中的每个层之间,层与层之间也存在依赖。比如:Controller层必须依赖Service层,例如:现在将Service层EmpServiceImpl删除了,然后EmpController层就会报错。
同样,Service层依赖Dao层。

依赖指的是 某某某 离不开 某某某
在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
我们系统架构或是设计的一个原则就是:高内聚 低耦合。
层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的。
而所谓的低耦合,就是我们熟称的炮友。
我想做到的是什么??删除EmpServiceImpl , EmpController不报错,EmpController中有new EmpServiceImpl( ) ; 这么new的会就表示和下层的EmpServiceImpl有关系了。

IOC-反转控制/ DI-依赖注入


在applicationContext.xml再写两行配置文件,在当前的整个配置文件中配置了三个bean,这三个bean就是对应了三个组件。下一步,计划在系统启动的时候,它就会把这三个组件准备好,放在一个容器里面,谁需要的时候就给谁用。
|
<?xml version="1.0" encoding="UTF-8"?>
<beans> <!-- 这个bean标签的作用是,id中的值,要和将来和ServletPath 中路径的名做对应,emp对应的就要EmpController这个类来处理。 --> <bean id="emp" class="com.hy.controller.EmpController"/>
<bean id="empService" class="com.hy.service.impl.EmpServiceImpl"/>
<bean id="empDao" class="com.hy.dao.impl.EmpDaoImpl"/> </beans> |


|
package com.hy.io;
import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException;
public class ClassPathXMLApplicationContext implements BeanFactory { private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
// 在默认构造方法中加载配置文件 public ClassPathXMLApplicationContext() {
try { InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
// 1,创建DocumentBuilderFactory工厂对象 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
// 2,创建DocumentBuilder对象 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// 3,得到Document对象( 注意导入org.w3c.dom包中的) Document document = documentBuilder.parse(inputStream);
// 4,获得所有的Bean标签 NodeList nodeList = document.getElementsByTagName("bean");
for (int i = 0, len = nodeList.getLength(); i < len; i++) { Node node = nodeList.item(i);
System.out.println(node.getNodeType() );//1,1,1
if( node.getNodeType() == node.ELEMENT_NODE) { Element element = (Element)node; String id = element.getAttribute("id"); String className = element.getAttribute("class");
boolean flag = map.containsKey(id);
if(flag == true) return;
Class clazz = Class.forName(className); Object o = clazz.newInstance();
map.put(id, o); } }
} catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
@Override public Object getBean(String id) { return map.get(id); }
public static void main(String[] args) { ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext(); } } |
运行main方法测试一下。
|
package com.hy.servlet;
import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Parameter;
import javax.servlet.ServletConfig; 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.hy.io.BeanFactory; import com.hy.io.ClassPathXMLApplicationContext; import com.hy.utils.StringUtil;
@WebServlet("*.do") public class DispatcherServlet extends HttpServlet { private BeanFactory beanFactory;
public DispatcherServlet() { }
@Override public void init(ServletConfig config) throws ServletException { super.init(config); beanFactory = new ClassPathXMLApplicationContext(); }
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置编码 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8");
// 假设url是: http://localhost:8080/mymvc2/hello.do // ServletPath是Servlet的访问路径: /hello.do // 思路是: // 第1步: /hello.do -> hello 或者 /book.do -> book // 第2步: hello -> HelloController 或者 book -> BookController String servletPath = request.getServletPath(); // /hello.do int lastDotIndex = servletPath.lastIndexOf(".do"); servletPath = servletPath.substring(1, lastDotIndex); // hello
// 通过ServletPath获取对应的Controller对象 // Object xxxController = map.get(servletPath); Object xxxController = beanFactory.getBean(servletPath);
String ac = request.getParameter("ac"); System.out.println("=======ac ===" + ac + "======"); if (StringUtil.isEmpty(ac)) ac = "index";
String methodReturnStr = null; try { // 这里只能try...catch异常,因为在重写的方法里,不能抛出比父类更大的异常 Method[] methods = xxxController.getClass().getDeclaredMethods();
if (methods != null) { for (Method method : methods) { if (ac.equals(method.getName())) { // 1,统一获取请求参数 // 1.1 获取当前方法的参数,返回参数数组 Parameter[] parameters = method.getParameters(); // 1.2 有几个参数就需要准备同等容量的Object类型的数组。这个数组用来存放参数的值得 Object[] parameterValues = new Object[parameters.length];
for (int i = 0, len = parameters.length; i < len; i++) { Parameter parameter = parameters[i];
// 1.3 从请求中获取参数的值 String parameterValue = request.getParameter(parameter.getName()); /** * 注意,这里没有考虑 复选框的情况,因为复选框name相同, * 打了好几个勾,一提交,返回给我们值的是一个数组 获取的方法: * request.getParameterValues(name); */
// 1.5 EmpController中delete方法的参数需要的是一个Integer类型, // 通过反射机制我们该方法需要的类型Parameter是Integer, // 但是前台传递到后台的是字符串”1”,而不是数字1,所以需要进行类型转换。 String typeName = parameter.getType().getName(); System.out.println("DispatcherServlet ==== typeName"+typeName);
//注意:这里一定要先将String 转成 Object Object parameterObj = parameterValue;
if(parameterObj != null) { //注意:这里如果需要完善, 还需要写Float,Double等类型 if("java.lang.Integer".equals(typeName)) { parameterObj = Integer.parseInt(parameterValue); } } // 1.4 将获取的参数值保存在Object类型的数组当中 //parameterValues[i] = parameterValue; parameterValues[i] = parameterObj; }
// 2. xxxController中的方法调用 // Object returnObj = method.invoke(xxxController, request, response); Object returnObj = method.invoke(xxxController,parameterValues);
// 3, 视图跳转处理 if (returnObj != null) { methodReturnStr = (String) returnObj; if (methodReturnStr.startsWith("redirect:")) { String redirectStr = methodReturnStr.substring("redirect:".length()); response.sendRedirect(request.getContextPath() + "/" + redirectStr); return; } else if (methodReturnStr.startsWith("forward:")) { String forwardtStr = methodReturnStr.substring("forward:".length()); request.getRequestDispatcher(forwardtStr).forward(request, response); return; } } return; } } throw new RuntimeException("ac值违法"); } } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } } |
我们将new EmpServiceImpl();删除了,去掉了依赖,如何赋值?
而且service层也依赖dao,改成null后,去掉了依赖,如何赋值?


在applicationContext.xml文件中先描述我们需要哪些组件。然后再描述组件与组件之间的依赖关系。XxxController中需要XxxService,XxxService中需要XxxDao。

|
package com.hy.io;
import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException;
public class ClassPathXMLApplicationContext implements BeanFactory { private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
// 在默认构造方法中加载配置文件 public ClassPathXMLApplicationContext() {
try { InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
// 1,创建DocumentBuilderFactory工厂对象 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
// 2,创建DocumentBuilder对象 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// 3,得到Document对象( 注意导入org.w3c.dom包中的) Document document = documentBuilder.parse(inputStream);
// 4,获得所有的Bean标签 NodeList nodeList = document.getElementsByTagName("bean");
for (int i = 0, len = nodeList.getLength(); i < len; i++) { Node node = nodeList.item(i); System.out.println(node.getNodeType());// 1,1,1
if (node.getNodeType() == node.ELEMENT_NODE) { Element element = (Element) node; String id = element.getAttribute("id"); String className = element.getAttribute("class");
boolean flag = map.containsKey(id);
if (flag == true) return;
Class clazz = Class.forName(className); // 创建bean对象 Object o = clazz.newInstance(); // 将bean对象存储到容器当中 map.put(id, o); // 到目前为止,我们将所有的bean,已经实例化(new了一个对象), // 并且存放到了容器当中,但是bean与bean对象之间的依赖关系还没有处理 } } System.out.println("================="); // 5, 组装bean之间的依赖关系,拿到bean对象之后,如果里面有property标签则进行组装 for (int i = 0, len = nodeList.getLength(); i < len; i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; String id = element.getAttribute("id"); // //element 就是获取的bean对象,通过getChildNodes()方法 //来获取这个对象有三个子节点,1和3是文本节点
NodeList childNodes = element.getChildNodes(); // System.out.println(childNodes.getLength());// 3,5,0 // //if (i == 1) { //查看第二个bean标签的5个子元素的类型分别是什么, // for (int j = 0; j < childNodes.getLength(); j++) { // //NodeType为 3,8,3,1,3, // //Node.TEXT_NODE = 3; // //Node.COMMENT_NODE = 8; // //Node.ELEMENT_NODE = 1; // System.out.print(childNodes.item(j).getNodeType()+","); // } //} } }
} catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
@Override public Object getBean(String id) { return map.get(id); }
public static void main(String[] args) { ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext(); } } |
|
package com.hy.io;
import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException;
public class ClassPathXMLApplicationContext implements BeanFactory { private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
// 在默认构造方法中加载配置文件 public ClassPathXMLApplicationContext() {
try { InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
// 1,创建DocumentBuilderFactory工厂对象 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
// 2,创建DocumentBuilder对象 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// 3,得到Document对象( 注意导入org.w3c.dom包中的) Document document = documentBuilder.parse(inputStream);
// 4,获得所有的Bean标签 NodeList nodeList = document.getElementsByTagName("bean");
for (int i = 0, len = nodeList.getLength(); i < len; i++) { Node node = nodeList.item(i);
System.out.println(node.getNodeType());// 1,1,1
if (node.getNodeType() == node.ELEMENT_NODE) { Element element = (Element) node; String id = element.getAttribute("id"); String className = element.getAttribute("class");
boolean flag = map.containsKey(id);
if (flag == true) return;
Class clazz = Class.forName(className); // 创建bean对象 Object o = clazz.newInstance(); // 将bean对象存储到容器当中 map.put(id, o); // 到目前为止,我们将所有的bean,已经实例化(new了一个对象), // 并且存放到了容器当中,但是bean与bean对象之间的依赖关系还没有处理 } } System.out.println("================="); // 5, 组装bean之间的依赖关系,拿到bean对象之后,如果里面有property标签则进行组装 for (int i = 0, len = nodeList.getLength(); i < len; i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; String id = element.getAttribute("id"); // // element 就是获取的bean对象,通过getChildNodes()方法 // 来获取这个对象有三个子节点,1和3是文本节点
NodeList childNodes = element.getChildNodes(); // System.out.println(childNodes.getLength());// 3,5,0 // // if (i == 1) { //查看第二个bean标签的5个子元素的类型分别是什么, // for (int j = 0; j < childNodes.getLength(); j++) { // //NodeType为 3,8,3,1,3, // //Node.TEXT_NODE = 3; // //Node.COMMENT_NODE = 8; // //Node.ELEMENT_NODE = 1; // System.out.print(childNodes.item(j).getNodeType()+","); // } // }
for (int j = 0; j < childNodes.getLength(); j++) { Node childNode = childNodes.item(j);
if (childNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(childNode.getNodeName())) { Element propertyElement = (Element)childNode;
//获取其name属性和ref属性 String propertyName = propertyElement.getAttribute("name"); String propertyRef = propertyElement.getAttribute("ref");
//找到ref对应的实例对象 Object refObj = map.get(propertyRef);
//当refObj设置到当前bean对应的对象的property属性上来 Object beanObj = map.get(id);
//获取该对象的类对象 Class beanClazz = beanObj.getClass();
//获得该类对象的属性 Field propertyField = beanClazz.getDeclaredField(propertyName);
//设置其可访问性 propertyField.setAccessible(true);
propertyField.set(beanObj, refObj); } } } }
} catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } }
@Override public Object getBean(String id) { return map.get(id); }
public static void main(String[] args) { ClassPathXMLApplicationContext applicationContext = new ClassPathXMLApplicationContext(); } } |
http://127.0.0.1:8080/mymvc4/emp.do?ac=add&ename=aaa&pwd=bbb

我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i