实训第六周/8/22/一个web项目的优化和升级(三)+菜系模块

菜系模块的完成

这里就不得不提到链接数据库时 我们所作的升级改造

升级前

在这里插入图片描述
c3p0-config.xml


<c3p0-config>
	<default-config>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="user">root</property>
		<property name="password">root</property>
		<property name="initialPoolSize">3</property>
		<!-- Max Pool Size如果未设置则默认为100,理论最大值为32767。最大连接数是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这会影响之后的数据库操作。在等待队列中,默认等待与服务器的连接的时间为15秒。 -->
		<property name="maxPoolSize">10</property>
	</default-config>

</c3p0-config>


daoimpl代码编写(添加方法)

public void insert(Note note) {
		// TODO Auto-generated method stub
		String sql="insert into note ( title ,author , content , img ,imgUrl) VALUES ( ?, ? , ?, ?, ?)";
		PreparedStatement pstmt =null;
	    Connection connection =DBUtils.getConnection();
	  // ResultSet rs=null;
		
	    try {
			pstmt=connection.prepareStatement(sql);
			pstmt.setString(1, note.getTitle());
			pstmt.setString(2, note.getAuthor());
			pstmt.setString(3, note.getContent());
			pstmt.setString(4, note.getImg());
			pstmt.setString(5, note.getImgUrl());
			pstmt.executeUpdate();	
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			DBUtils.jdbcClose( pstmt, connection);
			
		}
		
}

升级后
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcUtils {
	// 初始化连接池
	private static DataSource dataSource;
	static {
		dataSource = new ComboPooledDataSource();
	}
	//private static ComboPooledDataSource ds = new ComboPooledDataSource();
	public static DataSource getDataSource() {
		return dataSource;
	}
	/**
	 * 创建DbUtils常用工具类对象
	 */
	public static QueryRunner getQuerrRunner() {
		return new QueryRunner(dataSource);
	}
}

我们通过代码实现相同功能 时编写的区别就可以看出优化的效果

简介
QueryRunner是dbutils工具类的一个核心类
常用方法:

query(String sql, ResultSetHandler rsh);

update(…):

ResultSetHandler:封装结果集的接口,以下是其9个实现子类:

ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, ColumnListHandler, KeyedHandler, MapHandler, MapListHandler, ScalarHandler 。

★★BeanHandler:将查询结果的第一条记录封装成指定的bean对象,返回
★★BeanListHandler:将查询结果的每一条记录封装成指定的bean对象,将每一个bean对象放入list中 返回.

★MapListHandler:将查询结果的每一条记录封装map集合,将每一个map集合放入list中返回
★ScalarHandler:针对于聚合函数 例如:count(*) 返回的是一个Long值KeyedHandler:

(了解)ColumnListHandler:将查询结果的指定一列放入list中返回
(了解)MapHandler:将查询结果的第一条记录封装成map,字段名作为key,值为value 返回

(了解)ArrayHandler:将查询结果的第一条记录封装成数组,返回
(了解)ArrayListHandler:将查询结果的每一条记录封装成数组,将每一个数组放入list中返回




菜系模块

dao编写
  1. 建一个类FoodType
    FoodType [属性:int id+String typeName]
  2. dao包下 根据分析我们列出如下接口

这里省略了接口声明 直接到了实现类 且只写了关键代码

这一句建立数据连接池 外部声明
private QueryRunner qr=JdbcUtils.getQuerrRunner();

– 无返回内容 –

1.添加菜系 void add(FoodType foodtype);

sql=“insert into foodtype(typeName) values (?)”;
qr.update(sql,foodtype.getTypeName());

2.删除菜系 void delete(int id);

sql=“delete from foodtype where id=?”;
qr.update(sql,id);

3.修改菜系 update(FoodType foodtype);

sql=“update foodtype set typeName=? where id=?”
qr.update(sql,foodtype.getTypeName(),foodtype.getId());

– 有返回内容 –

4.按照ID查出数据 FoodType findById(int id);

select typeName from foodtype where id = ?

return qr.query(sql, new BeanHandler< FoodType>(FoodType.class), id);

异常 throw new RuntimeException

5.查询全部显示到了表 List< FoodType> query();

String sql=“select typeName from foodtype”;
query(sql,new BeanListHandler< FoodType>(FoodType.class))
异常 throw new RuntimeException();

新单词:BeanListHandler&BeanHandler---->通用的结果集处理器

可以把不同表中的每一行数据,封装成不同类型的对象

  1. BeanHandler:表示把结果集中的一行数据,封装成一个对象,专门针对结果集中只有一行数据的情况。

  2. BeanListHandler:表示把结果集中的多行数据,封装成一个对象的集合,针对结果集中有多行数据。
    6.(按照菜名查询) List< FoodType > query(String keyword);

try {
String sql=“select typeName from foodtype where typeName like ?”;
return qr.query(sql, new BeanListHandler< FoodType>(FoodType.class),"%"+keyword+"%");
} catch (SQLException e) {
throw new RuntimeException();
}

到了这里我们不可以着急进行业务逻辑的编写 优先进行

dao单元测试. 一张表 难度:简单
public class TestFoodType {
	public static void main(String[] args) {
		//测试获取数据库连接'
	    
		System.out.println(JdbcUtils.getQuerrRunner());
		FoodType foodtype=new FoodType();
		foodtype.setTypeName("印度餐");
		//FoodTypeDao ftd=new FoodTypeDao();
		 FoodTypeDao ftd=BeanFactory.getInstance("foodTypeDao", FoodTypeDao.class);
		//测试增加菜系
		//ftd.add(foodtype);
	//	删除菜系
		ftd.delete(5);
		//更新菜系
//		foodtype.setId(3);
//		ftd.update(foodtype);
		
		 
		//查询所有菜系
//		List<FoodType> list=ftd.query();
//		for(FoodType temp:list){
//			System.out.println(temp.getTypeName());
//		}
		 

		//按id查询菜系
		//FoodType ft =ftd.findById(1);
	  //System.out.println(ft.getTypeName());
		 //按菜系名查询

//		List<FoodType> list=ftd.query("中");
//	for(FoodType temp:list){
//			System.out.println(temp.getTypeName());
//		}
		 
	}	

}

在这里插入图片描述

测试的时候

FoodType foodtype=new FoodType();

直接暴漏了dao.impl 的具体细节如实现类名 而且关联性高

同时我们可以发现我们也可以通过反射得到类内部具体信息,也不安全

FoodTypeDao.class

原来我们的解决方法是

工厂模式(升级前)

工厂类下: new的方式拿到实体对象

public static IFoodTypeDao getFoodTypeDao(){

return new FoodTypeDao();
}
//getFoodTypeDao 拿到 隐藏名字+细节

其他问题 ------------------- --------------------- -----------

①由于工厂类集中了所有实例的创建逻辑(有一个写一个),违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;

②它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。

③当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;


优化后的工厂方法 :
使用配置文件+java反射机制来动态创建类的实例

核心技术
ResourceBundle与Properties读取配置文件

新工厂类:反射+newInstance()=拿到实体对象
Class.forName(className).newInstance();

import java.util.ResourceBundle;//这个类提供软件国际化的捷径

public class BeanFactory {
	 private static ResourceBundle bundle;
	 static{
		 //读取|加载属性文件 拿到很多信息    获取bundle
		 bundle=ResourceBundle.getBundle("instance");
	 }
	 //返回多个对象  灵活获取 使用泛型  传过来
	 public static <T> T getInstance(String key,Class<T> clazz){
	 try {
      String className=bundle.getString(key); //footTypeDao ->
  return (T) Class.forName(className).newInstance();
		} catch (Exception e) {
			 throw new RuntimeException(e);
		}
	 
	 }
}
//getInstance拿到

通过指定的key来获取具体的类名
bundle.getString(key)


新添加的属性文件 instance.properties (后缀名是固定的一般的命名规范是: 自定义名_语言代码_国别代)

#注释 key(  你的实体类名)=value(该类的具体路径)
#这里的value用于反射中forName(String className)来加载该类。
key=value


#Dao实体对象
foodTypeDao=com.xjo.dao.impl.FoodTypeDao
#foodTypeDao 就是上面的 key
#service实体对象
foodTypeService=com.xjo.service.impl.FoodTypeService

资源文件都必须是ISO-8859-1编码,因此,对于所有非西方语系的处理,都必须先将之转换为Java Unicode Escape格式。转换方法是通过JDK自带的工具native2ascii.


测试
IFoodTypeDao dao=BeanFactory.getInstance("foodTypeDao", IFoodTypeDao.class);

ftd.delete(5);
//更新菜系
//		foodtype.setId(3);
//		ftd.update(foodtype);
		
		 
//查询所有菜系
//		List<FoodType> list=ftd.query();
//		for(FoodType temp:list){
//			System.out.println(temp.getTypeName());
//		}
业务层接口-业务层实层 简单没有什么好说的
public class FoodTypeService implements IFoodTypeService{
	//FoodTypeDao实例对象
	IFoodTypeDao dao=BeanFactory.getInstance("foodTypeDao", IFoodTypeDao.class);
	
	@Override
	public void add(FoodType foodtype) {
		dao.add(foodtype);
		
	}

	@Override
	public void delete(int id) {
		dao.delete(id);
		
	}

	@Override
	public void updata(FoodType foodtype) {
		dao.update(foodtype);
		
	}

	@Override
	public List<FoodType> query() {
		return dao.query();
	}

	@Override
	public FoodType findById(int id) {
		return dao.findById(id);
		 
	}

	@Override
	public List<FoodType> query(String keyword) {
		return dao.query(keyword);
	 
	}

}

单元测试

java单元测试(@Test)

使用:

1、新建一个类 不需要写main方法,导入包org.junit.Test(可以快捷键自动导包 ctrl+shift+o)

2、运行:分两种情况:

1,点击左上角的运行按钮是运行所有的测试程序
2,在某个测试程序的方法名上右击Run As —>Junit Test 是运行该测试程序,其他的不运行(下图所示为运行的所有测试程序) 或者在选中方法的时候,直接点击左上角的运行按钮。
注意:方法权限只能是public,不能用static修饰。

业务层测试-看页页传参数和调用url(在接口文档中定义好的,一般由项目经理
控制层 (调用业务层的实现类) +从页面点击+ 跳转优化

< a target=“right” href="${pageContext.request.contextPath}/foodType?method=list">菜系管理< /a> 先到控制层 拿到数据 在跳转到显示页面传递调用哪个函数的参数list

在这里插入图片描述

package com.xjo.servlet;

import java.io.IOException;
import java.util.List;

import javax.servlet.RequestDispatcher;
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.xjo.entity.FoodType;
import com.xjo.factory.BeanFactory;
import com.xjo.service.IFoodTypeService;

@WebServlet("/foodType")
public class FoodTypeServlet extends HttpServlet {
	//FoodTypeService实例
	private IFoodTypeService    
	    foodTypeService=BeanFactory.getInstance("foodTypeService", IFoodTypeService.class);
	
	private Object uri;//路径地址 跳转 
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}

	 //自动生成的的初始化方法
	@Override
	public void init(ServletConfig config) throws ServletException {
		/*super.init(config); 未完成 思路是做判断 用哪个
	    List<FoodType> list=foodTypeService.query();
		config.getServletContext().getAttribute("foodtype", list);*/
		 
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String method=request.getParameter("method");//接受参数
		if("add".equals(method)){//菜系 增加
			add(request,response);
		}else if("list".equals(method)){
			list(request,response);//所有菜系显示
		}else if("update".equals(method)){
			update(request,response);
		}else if("delete".equals(method)){
			delete(request,response);//菜系 删除
		}else if("search".equals(method)){
			search(request,response);
		}else if("show".equals(method)){
			show(request, response);//菜系 更新时显示
		}

	}
	
	
	//添加菜系
	private void add(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
			 String name=request.getParameter("name");
			 FoodType foodtype=new FoodType();
			 foodtype.setTypeName(name);
			 foodTypeService.add(foodtype);
			 list(request,response);
			 
		}
	//显示所有菜系
	private void list(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
			
			List<FoodType> list=foodTypeService.query();
			request.setAttribute("list", list);
			uri=request.getRequestDispatcher("/sys/foodtype/cuisineList.jsp");

//拿到范围application 存list  这样其他人查询的时候就不用反复访问数据库	
//以后开发使用的是<redis 技术>  +  借助初始化方法 优先访问
 	request.getSession().getServletContext().setAttribute("foodtype", list);
			
goTo(request,response,uri);
		}
	//统一进行转发  写成一个方法 简化代码(优化) ,Object uri传入
		private void goTo(HttpServletRequest request, HttpServletResponse response,Object uri) throws ServletException, IOException {
	
    //就是重定向是两次请求,转发是一次请求,因此转发的速度要快于重定向
    
			if(uri instanceof RequestDispatcher){
			
	//服务器内部跳转 该URL会保持不变+以前的request中存放的变量不会失效
	
		( (RequestDispatcher)uri ).forward(request , response);
			}else{
			
	//重定向 浏览器中所显示的URL改变+以前的request中存放的变量不会失效
	//转发只能在站内跳转,重定向可以跳转到任意想要的地址
	
		response.sendRedirect(request.getContextPath()+(String)uri);
			}
}
		


	//在菜系更新中显示菜系名称
		private void show(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
			 
		}
		
		private void update(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
			 
		}
		
		private void delete(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
			 
		}
		//根据关键字搜菜系
		private void search(HttpServletRequest request, HttpServletResponse response)
				throws ServletException, IOException {
		 
		}}

页面显示
<!-- 过滤条件 -->
	<div id="QueryArea">
		<form action="${pageContext.request.contextPath }/foodType" method="post">
			<input type="hidden" name="method" value="search">
			<input type="text" name="keyword" title="请输入菜系名称">
			<input type="submit" value="搜索">
		</form>
	</div>

	<!-- 主内容区域(数据列表或表单显示) -->
	<div id="MainArea">
		<table class="MainArea_Content" align="center" cellspacing="0" cellpadding="0">
			<!-- 表头-->
			<thead>
				<tr align="center" valign="middle" id="TableTitle">
					<td>菜系编号</td>
					<td>菜系名称</td>
					<td width=30%>操作</td>
				</tr>
			</thead>
			<!--显示数据列表 -->
			<tbody id="TableData">
			<c:choose>
	             <c:when test="${not empty list}">
				<c:forEach items="${requestScope.list}" var="foodtype" varStatus="vs" >
					<tr>
					<!-- 如果用${foodtype.id},则在页面上显示的是数据库中的id值,因为在数据库中会删除记录,导致id不连续,而在页面上想使用连续的id -->
						<!-- c:forEach varStatus属性,迭代索引index当前这次迭代从 0 开始,迭代索引count当前迭代从 1 开始的迭代计数 -->
						<td>${vs.count}</td>
						<td>${foodtype.typeName}</td>
						<td>
							<a href="${pageContext.request.contextPath }/foodType?method=show&id=${foodtype.id}" class="FunctionButton">更新</a> 
							<a href="${pageContext.request.contextPath }/foodType?method=delete&id=${foodtype.id}" class="FunctionButton">删除</a>
						</td>
					</tr>
				</c:forEach>
			</c:when>
	<c:otherwise>
		没有数据!
	</c:otherwise>
</c:choose>		
			</tbody>
		</table>
		<!-- 其他功能超链接 -->
		<div id="TableTail" align="center">
			<div class="FunctionButton">
  <a href="${pageContext.request.contextPath }/sys/foodtype/saveCuisine.jsp">添加</a>
    			</div>
    		</div>
    	</div>

乱码处理+过滤器技术

直接复制 代码然后配置web.xml

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class EncodingFilter implements Filter {

	public void init(FilterConfig arg0) throws ServletException {

	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		request.setCharacterEncoding("utf-8");

		HttpServletRequest req = (HttpServletRequest) request;
		// 如果是get请求,交给EncodingRequest类处理
		if (req.getMethod().equals("GET")) {
			EncodingRequest er = new EncodingRequest(req);
			chain.doFilter(er, response);
		} else if (req.getMethod().equals("POST")) {
			chain.doFilter(request, response);
		}
	}

	public void destroy() {

	}
}

import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class EncodingRequest extends HttpServletRequestWrapper {
	private HttpServletRequest req;
	//构造方法接收从EncodingFilter中传过来的request,它是get请求
	public EncodingRequest(HttpServletRequest request) {
		super(request);
		this.req = request;
	}
	//获取request中的参数(包含中文的参数),并转换为utf-8
	public String getParameter(String name) {
		String value = req.getParameter(name);
		try {
			if(value!=null){
				value = new String(value.getBytes("iso-8859-1"), "utf-8");
			}
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
		return value;
	}
}


//web.xml
   <filter>
    <filter-name>encoding</filter-name>
    <filter-class>com.xjo.filter.EncodingFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值