JSP使用分层实现业务处理
在Java开发中,使用JDBC操作数据库的四个步骤如下:
②连接数据库(Connection con = DriverManager.getConnection();)
③操作数据库(PreparedStatement stat = con.prepareStatement(sql);stat.executeQuery();)
④关闭数据库,释放连接(con.close();)
也就是说,所有的用户都需要经过此四步进行操作,但是这四步之中有三步(①加载数据库驱动程序、②连接数据库、④关闭数据库,释放连接)对所有人都是一样的,而所有人只有在操作数据库上是不一样,那么这就造成了性能的损耗。
那么最好的做法是,准备出一个空间,此空间里专门保存着全部的数据库连接,以后用户用数据库操作的时候不用再重新加载驱动、连接数据库之类的,而直接从此空间中取走连接,关闭的时候直接把连接放回到此空间之中。
那么此空间就可以称为连接池(保存所有的数据库连接),但是如果要想实现此空间的话,则必须有一个问题要考虑?
1、 如果没有任何一个用户使用连接,那么那么应该维持一定数量的连接,等待用户使用。
2、 如果连接已经满了,则必须打开新的连接,供更多用户使用。
3、 如果一个服务器就只能有100个连接,那么如果有第101个人过来呢?应该等待其他用户释放连接
4、 如果一个用户等待时间太长了,则应该告诉用户,操作是失败的。
如果直接用程序实现以上功能,则会比较麻烦,所以在Tomcat 4.1.27之后,在服务器上就直接增加了数据源的配置选项,直接在服务器上配置好数据源连接池即可。在J2EE服务器上保存着一个数据库的多个连接。每一个连接通过DataSource可以找到。DataSource被绑定在了JNDI树上(为每一个DataSource提供一个名字)客户端通过名称找到在JNDI树上绑定的DataSource,再由DataSource找到一个连接。如下图所示:
JNDI的概念
JNDI是什么: java Naming and Directory Interface, java命名和目录接口// 通过名称将资源与服务进行关联
JNDI的作用和优点: 在应用与java对象或资源之间建立松耦合的逻辑关联,简化应用对于资源的配置以及维护工作//可以在更大的范围,不同应用之间共享资源
问题1
如何实现在Tomcat中发布一条信息供所有Web应用程序使用?
发布信息 :修改 Tomcat/conf/ context.xml文件
<Context> <Environment name="tjndi" value="hello JNDI" type="java.lang.String" /> </Context?>
获取资源:使用lookup()进行查找
//java.naming.Context提供了查找JNDI的接口 //初始化Context对象 Context ctx= new InitialContext(); //java:comp/env/为前缀 //调用lookup方法 String tes =(String)ctx.lookup("java:comp/env/tjndi"); out.print("JNDI:+testjndi");
为什么要使用连接池:
什么是连接池:
连接池是一个等待数据库连接的队列。
连接池的原理:
客户端向服务器端请求连接, 服务器端先看连接池中是否有空的连接,如果有空的连接就让该客户端连接, 如果没有空的连接,那就看现有连接数是否达到连接池限定的个数,如果没有达到就为该客户端创建一个连接,如果达到了那就让该客户端排队,等其他客户端断开连接了,就让该客户端连接。
连接池会设定一个等待时间,超过这个时间就就是连接超时了, 一般服务器性能和网速都会有影响。
Data Source 与连接池
javax.sql.DataSource接口的实现类
以连接池的形式对数据库连接进行管理
如何获取DataSource的实例
访问数据源:
Context的配置文件
属性
分成模式
使用Jsp的弊端: 页面展示和逻辑掺杂在一起阅读起来不清晰。不利于代码的维护和更新
三层架构
表示层:最外层,使用户直接能够访问,用于显示数据和接收用户输入的数据,为用户提供一种交互式操作界面
业务逻辑层:业务逻辑层的主要功能就是提供对业务逻辑处理的封装,在业务逻辑层中,通常会定义一些接口,表示层通过调用业务逻辑层的接口来实现各种操作
数据访问层:数据访问层就是实现对数据的保存和读取操作,数据访问,可以访问关系数据库,文本文件或XML文档等
层与层之间的关系
表示层依赖业务逻辑层,业务逻辑依赖于数据访问层各层之间的数据传递方向为请求与响应两个方向
使用三层开发的原则
1.上层依赖下层,依赖关系不跨层
2.下一层不能调用上一层
3.下一层不依赖上一层
4.在上一层不能出现下一层的概念
使用三层开发的优势和特点
1.下层不知道上层的存在
2.每一层仅仅知道它下一层的存在,而不知道另外的下层
使用分层架构的优点如下
1.职责划分清晰
2.无损替换
3.复用代码
4.降低了系统内部的依赖程度
连接池(DBCP与C3p0) 1): 之前的连接操作 拿到一个连接--->执行sql进行数据操作--->关闭连接 ps: 这样的话存在一些缺点的,比如每拿到一个连接用完后则就把这个连接关闭了,这很浪费,毕竟拿到一个连接等是需要时间的 这样也不能很好的对连接数进行控制 ,如果连接数过多的话,则可能会有内存泄漏服务器崩溃 2): 连接池 连接池则在创建一个数据库连接的缓冲池,在这个缓冲池创建时则可以在里边初始化一定的连接数,如需要获取连接时,则只需要到这个缓冲池中获取就行, 且用完后并不会把连接销毁,而是放回到缓冲池中,我们也可以设置同时的最大连接数等等,可以很好的避免之前连接操作的缺点 3): DataSource接口 对于数据库连接操作,有给我们提供了一个DataSource接口让我们来实现, 而这个接口一般会由一些开源组织或者服务器来实现 常用的有DBCP连接池与C3P0连接池, DataSource一般也叫数据源,也习惯把DataSource叫做连接池 2: DBCP连接池 1): DBCP连接池使用前提 需要导入两个jar包commons-dbcp.jar, commons-pool.jar 2): 数据源对象 数据源对象与数据库连接对象不同,它是产生(获取 )数据库连接对象的工厂 3: C3P0连接池 1): 使用前提需要导入c3p0的jar包 2): 使用
连接池的配置
文件上传
客户端提交表单,将文件传给服务器,就是文件上传.
表单标签 必须为 method="post"
enctype="multipart/form-data"
<h3>客户,请上传的头像</h3>
<form action="upload.jsp" method="post" enctype="multipart/form-data">
文件: <input type="file" name="userfile"><br><br>
<input type="submit" value="提交">
</form>
上传文件的基本要求:
上传文件的格式类型
上传文件的大小
上传文件的路径
上传文件的命名机制
java实现文件上传
1、jspsmartupload 文件上传组件 ,早些时间使用的多,简单
SmartUpload su = new SmartUpload();
su.initialize(pageContext);
su.upload();
//接表单值,如果有乱码,最好下载支持utf-8组件
out.print(su.getRequest().getParameter("username"));
String path = request.getServletContext().getRealPath("upload");
File f = new File(path);
if(!f.exists()){
f.mkdirs();
}
//上传文件
su.save(path);
//指定上传文件的目标路径 在服务器当前项目根目录下的upload目录
String path = request.getServletContext().getRealPath("upload");
File f = new File(path);
if(!f.exists()){
f.mkdirs();
}
//控制文件上传类型
su.setAllowedFilesList("jpg,png");
//控制上传文件的大小
su.setMaxFileSize(1024*100); 100KB
<%@ page import="com.jspsmart.upload.SmartUpload" %>
<%@ page import="java.io.File" %>
<%@ page import="com.jspsmart.upload.Files" %>
<%@ page import="java.util.UUID" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Random" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=utf-8" language="java" %>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>webrx-7031633</title>
</head>
<body>
<%
SmartUpload su = new SmartUpload();
su.initialize(pageContext);
su.setAllowedFilesList("jpg,png");
su.setMaxFileSize(1024*1024);
try {
su.upload();
//接表单值,如果有乱码,最好下载支持utf-8组件
out.print(su.getRequest().getParameter("username"));
//指定上传文件的目标路径 在服务器当前项目根目录下的upload目录
String path = request.getServletContext().getRealPath("upload");
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
//上传文件
//su.save(path); 将文件全部指上传到指定目录下,文件使用原来名子,如果有重复覆盖
//从0开始
int c = su.getFiles().getCount();
//out.print(su.getFiles().getFile(0).getFileName());
Files fs = su.getFiles();
for(int n=0;n<c;n++){
com.jspsmart.upload.File fff = fs.getFile(n);
//String name = fff.getFileName();//原文件名
//使用uuid命名
String ext = fff.getFileExt();
//String name = UUID.randomUUID().toString()+"."+ext;
//使用年月日信息命名
//SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssS");
//Random r = new Random();
//int nn = r.nextInt(9999999);
//String name = sdf.format(new Date())+"_"+String.format("%07d",nn)+"."+ext;
//使用命名编号
String fname = fff.getFileName();
String basename = fname.substring(0,fname.lastIndexOf("."));
String name = path+"/"+fname;
File nf = new File(name);
int num = 0;
while(nf.exists()){
fname = basename+"("+ ++num + ")."+ext;
name = path+"/"+fname;
nf = new File(name);
}
fff.saveAs("./upload/"+fname,SmartUpload.SAVE_VIRTUAL);
//fff.saveAs("./upload/"+name,SmartUpload.SAVE_VIRTUAL);
}
}catch (Exception e){
out.print(e.getMessage());
}
%>
</body>
</html>
2、Commons FileUpload apache文件上传组件 目前使用是最多的
使用2个jar包文件
commons-fileupload-1.3.2.jar
commons-io-2.5.jar
@WebServlet("/UpFile.action")
public class UpFile extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用apache commons fileupload 上传
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
String path = this.getServletContext().getRealPath("upload/");
//上传文件
if(isMultipart){
DiskFileItemFactory f = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(f);
try {
List<FileItem> items = upload.parseRequest(req);
for(FileItem ft : items){
if(ft.isFormField()){
//取得上传的表单字符串,
System.out.println(ft.getFieldName()+"="+ft.getString("utf-8"));
}else{
//如果没有选文件
//System.out.println(ft.getSize()); //0
//System.out.println(ft.getFieldName());//userfile 表单名
//System.out.println(ft.getName());//'' 空字符串
//System.out.println(ft.getContentType());//application/octet-stream
//97289
//userfile
//66ba2e6152f638cba76a99f77d0f74c31e86204c238d0-qIKBWz_fw658.jpg
//image/jpeg
//取得上传的文件名称
String filename = ft.getName();
//实现将文件写入到服务器指定的目录中
if(!"".equals(filename)) {
ft.write(new File(path, filename));
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
String path = this.getServletContext().getRealPath("upload/");
if(isMultipart){
DiskFileItemFactory f = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(f);
try {
Map<String,List<FileItem>> maps = upload.parseParameterMap(req);
//直接接表单username 字符串值
String username = maps.get("username").get(0).getString("utf-8");
//直接接userface单文件
FileItem ft1 = maps.get("userface").get(0);
if(!ft1.getName().equals("")){
ft1.write(new File(path,ft1.getName()));
}
//直接接checkbox 多选表单
List<FileItem> itemss = maps.get("love");
for(FileItem ftc : itemss){
System.out.println(ftc.getString("utf-8"));
}
//直接接userfile 文件数目不定
List<FileItem> items = maps.get("userfile");
for(FileItem ft : items){
if(!ft.getName().equals("")){
ft.write(new File(path,ft.getName()));
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、cos 文件上传组件 性能最好, 最快, 是国外一家出版社编写的
4、sun在servlet3.0 时候 内置 直接实现文件上传
headers
content-disposition
content-type
upfile.jsp
<h3>servlet3 客户,请上传的头像</h3>
<form action="upload.action" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="username"><br><br>
文件1: <input type="file" name="userfile1" multiple><br><br>
文件2: <input type="file" name="userfile2" ><br><br>
文件3: <input type="file" name="userfile3" ><br><br>
<input type="submit" value="提交">
</form>
upload.action
package com.fz.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
/**
* Created by webrx on 2017-05-06.
*/
@WebServlet("/upload.action") @MultipartConfig
public class Upload extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
//接表单值
String name = req.getParameter("username");
System.out.println(name);
//接单个文件文件
//Part uf = req.getPart("userfile");
//if(!uf.getSubmittedFileName().equals("")){
// uf.write(getServletContext().getRealPath("upload/")+uf.getSubmittedFileName());
//}
//接批量文件上传
Collection<Part> uf = req.getParts();
for(Part p : uf){
if(p.getHeader("content-type")==null) continue;
if(!p.getSubmittedFileName().equals("")){
p.write(getServletContext().getRealPath("upload/")+p.getSubmittedFileName());
}
}
//Part part = req.getPart("username");
/*
System.out.println(req.getParameter("username"));
Collection<Part> ps = req.getParts();
for(Part p : ps){
String name = p.getName();//表单名
//System.out.println(p.getHeader("content-disposition"));
//System.out.println(p.getHeader("content-type")); //如果为null 就是普通字符串表单
//System.out.println(p.getSubmittedFileName());
// p.getSubmittedFileName() 如果是null 则是普通表单
if(p.getHeader("content-type")==null){
//普通表单
}else{
//可能是文件,也可以是空文件
//form-data; name="userfile"; filename=""
//application/octet-stream
//实现文件上传到 c:/目录下
if(!p.getSubmittedFileName().equals("")) {
p.write("c:/"+p.getSubmittedFileName());
}
}
}