文章目录
- 本阶段技术体系
- 用项目理解原理
- controllers
- ClassPathXmlApplicationContext
- DispatcherServlet
- FruitServiceImpl
- Filter
本阶段技术体系
用项目理解原理
项目的目录
首先设置一个参数,这里里面用反射机制,获取方法的时候如果不设置会获取到arg[0],arg[1]…等等,设置了之后就会正常显示函数的名称
项目概念的理解
controllers
package com.myweb.controllers;
import com.myweb.dao.FruitDao;
import com.myweb.javabean.Fruits;
import com.myweb.mvc.ViewBaseServlet;
import com.myweb.servlets.FruitService;
import com.myweb.utils.test;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
/**
* ClassName: FruitControllers
* Package: com.myweb.controllers
* Description:
*
* @Author Thmiao
* @Create 2023/9/13 13:36
* @Version 1.0
*/
public class FruitControllers extends ViewBaseServlet {
private FruitService fruitService = null ;
private String index( String oper,String keyword,Integer pageNo,HttpServletRequest request ) throws Exception {
if(pageNo==null){
pageNo = 1;
}
HttpSession session = request.getSession() ;
// 如果这个不是点击搜索来或者的话
if(oper != null && "search".equals(oper)){
// 说明这个是点击搜索
pageNo = 1 ;
if(keyword==null){
keyword="";
}
session.setAttribute("keyword",keyword);
}else {
//说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
//此时keyword应该从session作用域获取
Object keywordObj = session.getAttribute("keyword");
if(keywordObj!=null){
keyword = (String)keywordObj ;
}else{
keyword = "" ;
}
}
session.setAttribute("pageNo",pageNo);
List<Fruits> fruitList = fruitService.getChoiceFruits(keyword , pageNo);
session.setAttribute("fruitList",fruitList);
//总记录条数
int pageCount = fruitService.getPageCount(keyword);
session.setAttribute("pageCount",pageCount);
return "index" ;
}
private String add(String fname,Double price,Integer fcount ,String remark) throws Exception {
Fruits fruit = new Fruits(fname , price , fcount , remark ) ;
fruitService.addFruit(fruit);
return "redirect:fruit.do";
}
}
这里是写的两个方法控制 首先和增加水果的方法
ClassPathXmlApplicationContext
package com.myweb.mvc.ioc;
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;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String,Object> beanMap = new HashMap<>();
public ClassPathXmlApplicationContext(){
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2.创建DocumentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
//3.创建Document对象
Document document = documentBuilder.parse(inputStream);
//4.获取所有的bean节点
NodeList beanNodeList = document.getElementsByTagName("bean");
for(int i = 0 ; i<beanNodeList.getLength() ; i++){
Node beanNode = beanNodeList.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE){
Element beanElement = (Element)beanNode ;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Class beanClass = Class.forName(className);
//创建bean实例
Object beanObj = beanClass.newInstance() ;
//将bean实例对象保存到map容器中
beanMap.put(beanId , beanObj) ;
//到目前为止,此处需要注意的是,bean和bean之间的依赖关系还没有设置
}
}
//5.组装bean之间的依赖关系
for(int i = 0 ; i<beanNodeList.getLength() ; i++){
Node beanNode = beanNodeList.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE) {
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
NodeList beanChildNodeList = beanElement.getChildNodes();
for (int j = 0; j < beanChildNodeList.getLength() ; j++) {
Node beanChildNode = beanChildNodeList.item(j);
if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
Element propertyElement = (Element) beanChildNode;
String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");
//1) 找到propertyRef对应的实例
Object refObj = beanMap.get(propertyRef);
//2) 将refObj设置到当前bean对应的实例的property属性上去
Object beanObj = beanMap.get(beanId);
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 (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String id) {
return beanMap.get(id);
}
}
这个文件的作用是把配置文件applicationContext.xml 里面的对象获取到生产一个实例,在其他文件的时候就不需要在建立其他的实例,增加了减小了代码的耦合性。而且这个的调用是在DispatcherServlet之前因为在它的init方法中有调用这个方法。
DispatcherServlet
package com.myweb.mvc;
import com.myweb.mvc.ioc.BeanFactory;
import com.myweb.mvc.ioc.ClassPathXmlApplicationContext;
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;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet{
private BeanFactory beanFactory ;
public DispatcherServlet(){
}
public void init() throws ServletException {
super.init();
beanFactory = new ClassPathXmlApplicationContext();
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("UTF-8");
//假设url是: http://localhost:8080/pro15/hello.do
//那么servletPath是: /hello.do
// 我的思路是:
// 第1步: /hello.do -> hello 或者 /fruit.do -> fruit
// 第2步: hello -> HelloController 或者 fruit -> FruitController
String servletPath = request.getServletPath();
servletPath = servletPath.substring(1);
int lastDotIndex = servletPath.lastIndexOf(".do") ;
servletPath = servletPath.substring(0,lastDotIndex);
Object controllerBeanObj = beanFactory.getBean(servletPath);
String operate = request.getParameter("operate");
if(operate==null){
operate = "index" ;
}
try {
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
for(Method method : methods){
if(operate.equals(method.getName())){
//1.统一获取请求参数
//1-1.获取当前方法的参数,返回参数数组
Parameter[] parameters = method.getParameters();
//1-2.parameterValues 用来承载参数的值
Object[] parameterValues = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String parameterName = parameter.getName() ;
//如果参数名是request,response,session 那么就不是通过请求中获取参数的方式了
if("request".equals(parameterName)){
parameterValues[i] = request ;
}else if("response".equals(parameterName)){
parameterValues[i] = response ;
}else if("session".equals(parameterName)){
parameterValues[i] = request.getSession() ;
}else{
//从请求中获取参数值
String parameterValue = request.getParameter(parameterName);
String typeName = parameter.getType().getName();
Object parameterObj = parameterValue ;
if(parameterObj!=null) {
if ("java.lang.Integer".equals(typeName)) {
parameterObj = Integer.parseInt(parameterValue);
}
if ("java.lang.Double".equals(typeName)){
parameterObj = Double.parseDouble(parameterValue);
}
}
parameterValues[i] = parameterObj ;
}
}
//2.controller组件中的方法调用
method.setAccessible(true);
if(parameterValues==null) {
System.out.println("他不是null");
}else {
for(Object parameterObj : parameterValues){
System.out.println(parameterObj);
}
}
Object returnObj = method.invoke(controllerBeanObj,parameterValues);
//3.视图处理
String methodReturnStr = (String)returnObj ;
if(methodReturnStr.startsWith("redirect:")){ //比如: redirect:fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
response.sendRedirect(redirectStr);
}else{
super.processTemplate(methodReturnStr,request,response); // 比如: "edit"
}
}
}
/*
}else{
throw new RuntimeException("operate值非法!");
}
*/
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
// 常见错误: IllegalArgumentException: argument type mismatch
这个的实现主要有
1.URL拆解,看它会掉用哪个函数,获取到这个函数的名称。
2.获取到controllers 里面的方法,利用反射获取到参数和方法
3.通过返回的类型,看他调用什么方法统一一起调用
FruitServiceImpl
package com.myweb.controllers;
import com.myweb.dao.FruitDao;
import com.myweb.javabean.Fruits;
import com.myweb.mvc.ViewBaseServlet;
import com.myweb.servlets.FruitService;
import com.myweb.utils.test;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
/**
* ClassName: FruitControllers
* Package: com.myweb.controllers
* Description:
*
* @Author Thmiao
* @Create 2023/9/13 13:36
* @Version 1.0
*/
public class FruitControllers extends ViewBaseServlet {
private FruitService fruitService = null ;
private String index( String oper,String keyword,Integer pageNo,HttpServletRequest request ) throws Exception {
if(pageNo==null){
pageNo = 1;
}
HttpSession session = request.getSession() ;
// 如果这个不是点击搜索来或者的话
if(oper != null && "search".equals(oper)){
// 说明这个是点击搜索
pageNo = 1 ;
if(keyword==null){
keyword="";
}
session.setAttribute("keyword",keyword);
}else {
//说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
//此时keyword应该从session作用域获取
Object keywordObj = session.getAttribute("keyword");
if(keywordObj!=null){
keyword = (String)keywordObj ;
}else{
keyword = "" ;
}
}
session.setAttribute("pageNo",pageNo);
List<Fruits> fruitList = fruitService.getChoiceFruits(keyword , pageNo);
session.setAttribute("fruitList",fruitList);
//总记录条数
int pageCount = fruitService.getPageCount(keyword);
session.setAttribute("pageCount",pageCount);
return "index" ;
}
private String add(String fname,Double price,Integer fcount ,String remark) throws Exception {
Fruits fruit = new Fruits(fname , price , fcount , remark ) ;
fruitService.addFruit(fruit);
return "redirect:fruit.do";
}
}
这个FruitServiceImpl 代替了之前的fruitDao ,让fruitDao 一开始可以设置为空然后优化了方法。
Filter
Filter是在运行 DispatcherServlet前(也就是与后端交互前要经过这个)
1) Filter也属于Servlet规范
2) Filter开发步骤:新建类实现Filter接口,然后实现其中的三个方法:init、doFilter、destroy
配置Filter,可以用注解@WebFilter,也可以使用xml文件 <filter> <filter-mapping>
3) Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter("*.do")表示拦截所有以.do结尾的请求
4) 过滤器链
1)执行的顺序依次是: A B C demo03 C2 B2 A2
2)如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的
3)如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序
还是推荐下载下来好好看项目比较方法实在。。。。