自定义MVC完整版

前言

来自全世界各地的朋友们,你们好!小编前面的博客中有简单的介绍MVC,建议初学者先去看之前写的博客,再连贯起来,关于自定义mvc的博客链接如下表格(从上往下看,就是从最初的版本演变成最终的自定义MVC完整的版本的过程):

博客标题博客链接
了解自定义MVC.https://blog.csdn.net/men_ma/article/details/105802883.
自定义MVC加减法(案例). https://blog.csdn.net/men_ma/article/details/106222591.
自定义MVC完整版.https://blog.csdn.net/men_ma/article/details/106739503.

1.需要实现的效果图(目标)

在这里插入图片描述

2.做增删改查的前两种方案的弊端

2.1第一种方案:jsp版本(jsp页面+servlet)

在这里插入图片描述
弊端:同样是处理书籍的逻辑业务(crud),创建的类过多,假如我有100张表那么我要创建400个处理"增删改查"的"处理业务逻辑"的servlet类

2.2第二种方案:if分支处理
@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String methodName = req.getParameter("methodName");
		if("list".equals(methodName)) {
			list(req, resp);
		}else if("add".equals(methodName)) {
			add(req, resp);
		}else if("toEdit".equals(methodName)) {
			toEdit(req, resp);
		}else if("edit".equals(methodName)) {
			edit(req, resp);
		}else if("del".equals(methodName)) {
			del(req, resp);
		}
	}

思考:能不能把所有相关的一组业务逻辑(比如都是关于书籍的操作)放在一个类中进行处理?
发现:这种处理方式少维护"n-1"个类
弊端

  1. if条件分支过多,代码过于"臃肿",也就是说太胖了,看起来不好看(分析:if代码块中就是调用了当前类的对应方法。 处理:“反射动态调用方法”)

  2. 处理前端jsp传递到后端值得封装"代码量过大"(分析:说白了就是给指定的"类属性"赋值 处理:“通过反射读写属性”)

  3. 处理完"业务逻辑"应该"跳转指定页面"(分析:不同的逻辑处理完跳转的页面不同 ,代码的位置过于混乱,我们希望统一管理 处理:“利用"xml建模"将"结果码"页面统一配置”)

3.自定义mvc框架工作原理图

在这里插入图片描述
原理图中的讲解思路(如下):

在这里插入图片描述

4.整个项目所需的所有包及类

在这里插入图片描述

5.所需的数据库表及数据

在这里插入图片描述

在这里插入图片描述

6.项目源代码

Job.java(实体类):

package com.xiaoqing.entity;

import java.sql.Timestamp;

public class Job {
	private String id;
	private String job;
	private String company;
	private String address;
	private String salary;
	private String url;
	private String quary;
	private Timestamp timedate;
	public Timestamp getTimedate() {
		return timedate;
	}
	public void setTimedate(Timestamp timedate) {
		this.timedate = timedate;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public String getCompany() {
		return company;
	}
	public void setCompany(String company) {
		this.company = company;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getSalary() {
		return salary;
	}
	public void setSalary(String salary) {
		this.salary = salary;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getQuary() {
		return quary;
	}
	public void setQuary(String quary) {
		this.quary = quary;
	}
	
	public Job() {}
	public Job(String id, String job, String company, String address, String salary, String url, String quary) {
		this.id = id;
		this.job = job;
		this.company = company;
		this.address = address;
		this.salary = salary;
		this.url = url;
		this.quary = quary;
	}
	public Job(String job, String company, String address, String salary, String url, String quary) {
		this.job = job;
		this.company = company;
		this.address = address;
		this.salary = salary;
		this.url = url;
		this.quary = quary;
	}
	@Override
	public String toString() {
		return "Job [id=" + id + ", job=" + job + ", company=" + company + ", address=" + address + ", salary=" + salary
				+ ", url=" + url + ", quary=" + quary + "]";
	}
	public Job(String id, String job, String company, String address, String salary, String url, String quary,
			Timestamp timedate) {
		super();
		this.id = id;
		this.job = job;
		this.company = company;
		this.address = address;
		this.salary = salary;
		this.url = url;
		this.quary = quary;
		this.timedate = timedate;
	}
}

DispatcherServlet .java(中央控制器):

/**
 * 中央控制器
 * 作用:接受请求,通过请求寻找处理请求的对应的子控制器
 * @author 晴sister
 *
 * https://i.csdn.net/#/uc/profile
 */

//配置中央控制器类(注):不要把*.action写成/*,不然连jsp文件也一起配置,此处只需要配置后缀名为.action的文件
@WebServlet(name="dispatcherServlet",urlPatterns="*.action")
public class DispatcherServlet extends HttpServlet{
	private static final long serialVersionUID = 3087790807485948710L;
	//建模
	private ConfigModel configModel;
	
	//初始化
	@Override
	public void init() throws ServletException {
		try {
			configModel=ConfigModelFactory.build();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//拿到发出的请求:http://localhost:8080/T243_mvc2/job.action?methodName=list
		String uri = req.getRequestURI();
		//System.out.println(uri);
		//截取job
		String path = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));//book
		//通过建模拿到<action>标签
		ActionModel actionModel = configModel.pop(path);
		//如果没有配置<action>标签
		if(actionModel==null) {
			//则抛出异常
			throw new RuntimeException(path+" action 标签没有配置");
		}
		try {
			//实例化处理网络请求URL的类
			//action就相当于JobAction
			//反射实例化  newInstance
			Action action =(Action)Class.forName(actionModel.getType()).newInstance();
			//动态封装参数
			if(action instanceof ModelDriver) {
				//如果实现了模型驱动接口,那么就强转为ModelDriver   此时action代表JobAction
				ModelDriver md = (ModelDriver)action;
				//将前端jsp参数传递到后端的所有值封装到业务模型类中
				//这个方法会遍历map<key, value>中的key,如果md.getModel()中有这个属性,就把这个key对应的value值赋给md.getModel()的属性。
				BeanUtils.populate(md.getModel(), req.getParameterMap());
			}
			//动态调用方法:解决if分支代码块的问题
			String code = action.excute(req, resp);//得到结果码
			//通过结果码去找对应跳转的哪个页面
			ForwardModel forwardModel = actionModel.pop(code);
			//得到path :reg.jsp(例如)
			String jspPath=forwardModel.getPath();
			//如果是重定向
			if(forwardModel.getRedirect()) {
				resp.sendRedirect(req.getServletContext()+jspPath);
			}else {
				//不是重定向,转发
				req.getRequestDispatcher(jspPath).forward(req, resp);
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
	}
}

Action.java(子控制器接口):


/**
 * 子控制器(相当于火车轨)
 * 作用:用来处理浏览器发送过来的请求
 * @author 晴sister
 *
 * https://i.csdn.net/#/uc/profile
 */
public interface Action {
	//执行业务逻辑代码
	String excute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException ;
}

ActionSupport .java(子控制器):

/**
 * 处理if分支问题,动态调用当前类的其他方法add/del/edit
 * @author 晴sister
 *
 * https://i.csdn.net/#/uc/profile
 */
public class ActionSupport implements Action{
	@Override
	public String excute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		String methodName = req.getParameter("methodName");
		//this指的是JobAction
		//通过反射得到方法名
		Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
		//打开通道
		m.setAccessible(true);
		//相当于动态调用del(req,resp)
		//method.invoke()方法:用来执行某个的对象的目标方法
		return (String) m.invoke(this, req,resp);
	}
}

ModelDriver.java(模型驱动接口):

/**
 * 模型驱动接口
 * @author 晴sister
 *
 * https://i.csdn.net/#/uc/profile
 */
public interface ModelDriver<T> {
	//T 在此代表private Job job = new Job();
	//得到具体的类
	T getModel();
}

PageTag .java(封装分页标签助手类):

public class PageTag extends BodyTagSupport{
	private static final long serialVersionUID = -258029245678348536L;
	private PageBean pageBean;

	public PageBean getPageBean() {
		return pageBean;
	}
	public void setPageBean(PageBean pageBean) {
		this.pageBean = pageBean;
	}
	@Override
	public int doStartTag() throws JspException {
		// TODO Auto-generated method stub
		JspWriter out = pageContext.getOut();
		try {
			out.print(toHTML());
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}	
		return super.doStartTag();
	}
	private String toHTML() {
		// TODO Auto-generated method stub
		StringBuilder sb=new StringBuilder();
		//上一次查询的form表单的HTML拼接
		//System.out.println(pageBean.getUrl());
		sb.append(" <form id='pageBeanForm' action='"+pageBean.getUrl()+"' method='post'>");
		//查第几页的数据
		sb.append(" <input type='hidden' name='page'>");
		Map<String, String[]> parameterMap = pageBean.getParameterMap();
		if(parameterMap.size()>0) {
			Set<Entry<String,String[]>> entrySet = parameterMap.entrySet();
			for (Entry<String, String[]> entry : entrySet) {
				if(!"page".equals(entry.getKey())) {
					for (String val : entry.getValue()) {
						sb.append("<input type='hidden' value='"+val+"' name='"+entry.getKey()+"'>");
					}
				}
			}
		}
		sb.append("</form> ");	
		//默认展示前面4页,当前页 ,后面5也
		int page=pageBean.getPage();
		int max=pageBean.getMaxPage();
		int before=page>4?4:page-1;
		int after=10-1-before;//5
		after=max-page>after?after:max-page;
		//用来控制上一页的点击按钮特效的
		boolean startFlag=page==1;
		//用来控制下一页的点击按钮特效的
		boolean endFlag=page==max;
//      拼接分页条
		sb.append("<ul class='pagination'>");
	    sb.append("<li class='page-item "+(startFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage(1)'>首页</a></li>");
	    sb.append("<li class='page-item "+(startFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.getPrevPage()+")'>&lt;</a></li>");
//	        代表了当前页的前4页
	        for (int i = before; i > 0 ; i--) {
	            sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage("+(page-i)+")'>"+(page-i)+"</a></li>");
	        }
	        sb.append("<li class='page-item active'><a class='page-link' href='javascript:gotoPage("+pageBean.getPage()+")'>"+pageBean.getPage()+"</a></li>");
//	        代表了当前页的后5页
	        for (int i = 1; i <= after; i++) {
	            sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage("+(page+i)+")'>"+(page+i)+"</a></li>");
	        }
	        sb.append("<li class='page-item "+(endFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.getNextPage()+")'>&gt;</a></li>");
	        sb.append("<li class='page-item "+(endFlag ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.getMaxPage()+")'>尾页</a></li>");
	        sb.append("<li class='page-item go-input'><b>到第</b><input class='page-link' type='text' id='skipPage' name='' /><b>页</b></li>");
	        sb.append("<li class='page-item go'><a class='page-link' href='javascript:skipPage()'>确定</a></li>");
	        sb.append("<li class='page-item'><b>共"+pageBean.getTotal()+"条</b></li>");
	        sb.append("</ul>");
//	        拼接分页的js代码
	        sb.append("<script type='text/javascript'>");
	        sb.append("function gotoPage(page) {");
	        sb.append("document.getElementById('pageBeanForm').page.value = page;");
	        sb.append("document.getElementById('pageBeanForm').submit();");
	        sb.append("}");
	        sb.append("function skipPage() {");
	        sb.append("var page = document.getElementById('skipPage').value;");
	        sb.append("if (!page || isNaN(page) || parseInt(page) < 1 || parseInt(page) > '+max+') {");
	        sb.append("alert('请输入1~N的数字');");
	        sb.append("return;");
	        sb.append("}");
	        sb.append("gotoPage(page);");
	        sb.append("}");
	        sb.append("</script>");
	        return sb.toString();
	}
}

BaseDao.java(通用增删改查方法类):

public class BaseDao<T> {
public List<T> executeQuery(String sql,Class clz,PageBean pageBean) throws SQLException, InstantiationException, IllegalAccessException{
		Connection con = DBAccess.getConnection();
		PreparedStatement pst = null;
		ResultSet rs = null;
		//判断是否分页
		if(pageBean!=null&&pageBean.isPagination()) {
			//需要分页的
			//算符合条件的总记录数
			String countSql=getCountSql(sql);
			//重新执行countSql
			pst=con.prepareStatement(countSql);
			rs=pst.executeQuery();
			if(rs.next()) {
				//设置总记录数
				pageBean.setTotal(rs.getLong(1)+ "");
			}
			//查询出符合条件的结果集
			String pageSql=getPageSql(sql,pageBean);
			pst=con.prepareStatement(pageSql);
			rs=pst.executeQuery();
		}else {
			//不需要分页的
			pst=con.prepareStatement(sql);
			rs=pst.executeQuery();
		}
		List<T> list=new ArrayList<T>();
		T t;//为了节省内存,所以定义在while外面
		while(rs.next()) {
			/**
			 * 1.实例化一个book对象(该对象是空的,不是null)
			 * 2.取book的所有属性,然后给其赋值
			 * 	2.1 获取所有属性对象
			 * 	2.2 给属性对象赋值
			 * 3.赋完值的book对象装进list容器中
			 */
			//反射实例化
			t =(T)clz.newInstance();
			//反射获取所以属性对象
			Field[] fields = clz.getDeclaredFields();
			//遍历
			for (Field field : fields) {
				//打开通道
				field.setAccessible(true);
				//给属性对象赋值
				field.set(t, rs.getObject(field.getName()));
				//System.out.println(field.getName());
			}
			//把对象增加到集合
			list.add(t);
		}
		DBAccess.close(con, pst, rs);
		return list;
	}

	public String getCountSql(String sql) {
		// TODO Auto-generated method stub
		return "select count(1) from ("+sql+") t";
	}
	
	/**
	 * sql=select * from t_mvc_book where true and bname like '%圣墟%';
	 * countSql=select count(1) from (select * from t_mvc_book where true and bname like '%圣墟%')
	 * pageSql=select * from t_mvc_book where true and bname like '%圣墟%' limit 10,10;
	 */
	
	public String getPageSql(String sql,PageBean pageBean) {
		
		return sql+" limit "+pageBean.getStartIndex()+","+pageBean.getRows();
	}
	
	/**
	 * 
	 * @param sql
	 * @param t    book
	 * @param attrs   bid,bname,price
	 * @return
	 * @throws SQLException
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	public int executeUpdate(String sql,T t,String[] attrs) throws SQLException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
		Connection con = DBAccess.getConnection();
		PreparedStatement ps = con.prepareStatement(sql);
		System.out.println(sql);
	/*	ps.setObject(1, book.getBid());
		ps.setObject(2, book.getBname());
		ps.setObject(3, book.getPrice());*/
		//以上三行代码的意思是,将参数对象t中的属性值,赋值给object对象
		int loop=1;//下标
		Field f=null;
		//attrs={"bid","bname","price"}
		for (String attr : attrs) {
			 f = t.getClass().getDeclaredField(attr);
			 f.setAccessible(true);
			 //给对象赋值
			 ps.setObject(loop++, f.get(t));
		}
		int n = ps.executeUpdate();
		DBAccess.close(con, ps, null);
		return n;
	}
}

JobDao .java(处理sql语句):

public class JobDao extends BaseDao<Job>{
	//查询所有及单个查询和模糊查询
	public List<Job> list(Job job,PageBean pageBean) throws InstantiationException, IllegalAccessException, SQLException{
		String sql="select * from t_solr_job where true";
		String j = job.getJob();
		if(StringUtils.isNotBlank(j)) {
			sql+=" and job like '%"+j+"%'";
		}
		String id = job.getId();
		if(StringUtils.isNotBlank(id)) {
			sql+=" and id='"+id+"'";
		}
		return super.executeQuery(sql, Job.class, pageBean);
	}
	//增加
	public int add(Job job) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, SQLException {
		job.setId(UUID.randomUUID().toString());
		String sql="insert into t_solr_job(id,job,company,address,salary,url,quary,timedate) values(?,?,?,?,?,?,?,?)";
		return super.executeUpdate(sql, job, new String[] {"id","job","company","address","salary","url","quary","timedate"});
	}
	//修改
	public int edit(Job job) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, SQLException {
		String sql="update t_solr_job set job=?,company=?,address=?,salary=?,url=?,quary=? where id=?";
		return super.executeUpdate(sql, job, new String[] {"job","company","address","salary","url","quary","id"});
	}
	//删除
	public int del(Job job) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, SQLException {
		String sql="delete from t_solr_job where id=?";
		return super.executeUpdate(sql, job, new String[] {"id"});
	}
}

JobAction .java(处理业务逻辑):

/**
 * 子控制器:处理业务逻辑
 * @author 晴sister
 *
 * https://i.csdn.net/#/uc/profile
 */
public class JobAction extends ActionSupport implements ModelDriver<Job>{

	private Job job=new Job();
	private JobDao jobDao=new JobDao();
	
	@Override
	public Job getModel() {
		// TODO Auto-generated method stub
		return job;
	}
	
	/**
	 * 查询所有
	 * @param req
	 * @param resp
	 * @return
	 */
	public String list(HttpServletRequest req,HttpServletResponse resp) {
		PageBean pageBean =new PageBean();
		pageBean.setRequest(req);
		try {
			List<Job> list = this.jobDao.list(job, pageBean);
			req.setAttribute("jobs", list);
			req.setAttribute("pageBean", pageBean);
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "list";
	}
	
	public String toAdd(HttpServletRequest req,HttpServletResponse resp) {
		
		return "toAdd";
	}
	
	public String add(HttpServletRequest req,HttpServletResponse resp) {
		try {
			this.jobDao.add(job);
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "toList";
	}
	
	public String toEdit(HttpServletRequest req,HttpServletResponse resp) {
			try {
				Job j = this.jobDao.list(job, null).get(0);
				req.setAttribute("j", j);
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return "toEdit";
		}
	
	public String edit(HttpServletRequest req,HttpServletResponse resp) {
		try {
			this.jobDao.edit(job);
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "toList";
	}
	
	public String del(HttpServletRequest req,HttpServletResponse resp) {
		try {
			this.jobDao.del(job);
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "toList";
	}
}

mvc.xml(建模得到结果码匹配跳转相应的界面):

<?xml version="1.0" encoding="UTF-8"?>
<config>

	<action path="/job" type="com.xiaoqing.web.JobAction">
		<forward name="list" path="/jobList.jsp" redirect="false" />
		<forward name="toAdd" path="/jobAdd.jsp" redirect="" />
		<forward name="toEdit" path="/jobEdit.jsp" redirect="false" />
		<forward name="toList" path="/job.action?methodName=list" redirect="" />
	</action>
</config>

jobList.jsp(查询所有展示页面):

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
     <%@taglib uri="/xiaoqing" prefix="z" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>博客展示</title>
<style type="text/css">
.page-item input {
	padding: 0;
	width: 40px;
	height: 100%;
	text-align: center;
	margin: 0 6px;
}

.page-item input,
.page-item b {
	line-height: 38px;
	float: left;
	font-weight: 400;
}

.page-item.go-input {
	margin: 0 10px;
}

</style>
</head>
<body>
<form class="form-inline" action="${pageContext.request.contextPath }/job.action?methodName=list" method="post">
  <div class="form-group mb-2">
    <input type="text" name="job" class="form-control-plaintext" id="staticEmail2"  placeholder="请输入岗位">
  </div>
  <button type="submit" class="btn btn-primary mb-2">查询</button>
  <!--
  	href="/bookAdd.jsp"  相对路径 ,相对的是Tomcat工程的根目录
  	href="bookAdd.jsp" 相当于请求
  	${pageContext.request.contextPath }/bookAdd.jsp 带上项目名的绝对路径
  	href="${pageContext.request.contextPath }/book.action?methodName=toAdd"通过后台转发到前台的jsp页面
    -->
  <a href="${pageContext.request.contextPath }/jobAdd.jsp" class="btn btn-primary mb-2 ml-4">新增</a>
</form>

<table class="table table-striped">
  <thead>
    <tr>
      <th scope="col">职位编号</th>
      <th scope="cosl">工作岗位</th>
      <th scope="col">公司名称</th>
      <th scope="col">公司地址</th>
      <th scope="col">薪水</th>
      <th scope="col">url</th>
      <th scope="col">学历</th>
      <th scope="col">爬取时间</th>
      <th scope="col">操作</th>
    </tr>
  </thead>
  <tbody>
  <c:forEach var="b" items="${jobs }">
    <tr>
      <td>${b.id }</td>
      <td>${b.job }</td>
      <td>${b.company }</td>
      <td>${b.address }</td>
      <td>${b.salary }</td>
      <td><a target="_blank" href="${b.url }">${b.url }</a></td>
       <td>${b.quary }</td>
       <td>${b.timedate }</td>
      <td>
      	<a href="${pageContext.request.contextPath }/job.action?methodName=del&id=${b.id}" class="btn btn-sm btn-danger btn-primary mb-2 ml-4">删除</a>
      	<a href="${pageContext.request.contextPath }/job.action?methodName=toEdit&id=${b.id}" class="btn btn-sm btn-success btn-primary mb-2 ml-4">修改</a>
      </td>
    </tr>
  </c:forEach>
  </tbody>
</table>
 <z:page pageBean="${pageBean }"></z:page> 
</body>
</html>

还有一些类没有放上来,由于小编的博客中有这些类,所以就不再重复上传啦!!这里给链接: 通用分页一. xml建模.

7.总结

自定义mvc很强大,希望大家多去理解思路!搞懂自定义mvc,十五分钟左右就可以写一个增删改查及分页查询完整版!!会省下很多的代码量,便于提高开发效率!

整个mvc就OK了
欢迎大家评论!!!
谢谢!!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值