注:此博客为学习笔记,没有任何参考价值
目录
Javaweb技术背景
Internet上供外界访问的Web资源分为:静态web资源(如html 页面):指web页面中供人们浏览的数据始终是不变。动态web资源:指web页面中供人们浏览的数据是由程序产生的,不同时间点访问web页面看到的内容各不相同。静态web资源开发技术:HTML、CSS。动态web资源开发技术:JavaScript、JSP/Servlet、ASP、PHP等。在Java中,动态web资源开发技术统称为Java Web。
第一次 tomcat
安装Tomcat并启动
第二次 eclipse配置tomcat
eclpse配置Tomcat
第三次 web项目servlet初步
新建web项目file-new-Dynamic Web Project
新建servlet,右击chapter03-new-servlet 命名
next-next不勾第一个框框 -finish
部署和访问Servlet,reemove进入wed应用界面
第四次 web实现交互
doget与dopost实现 收到doget请求
第五次 servlet使用方法
乱码问题解决方法:
(1)response.setContentType("text/html;charset=utf-8");
(2)response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type"text/html;charset=utf-8");
实现请求重定向
在HttpServletResponse接口中,定义sendRedirect()方法用于生成302响应码和Location响应头,从而通知客户端重新访问Location响应头中指定的URL,sendRedirect()方法语法:public class sendRedirect(java.long.String location) throws java.io.IOException
第六次 Servlet
浏览器访问网站首界面——到网站首界面indexServlet——判断用户是否登录-是时显示登录用户的信息点击“退出”-用户退出登录界面logoutServlet回到网站首界面IndexServlet—如果否就进入登录界面login.html——处理用户登录信息LoginServlet——判断用户名与密码是否正确-否就提示错误——是就到显示登录用户信息到“退出”
1.创建封装用户信息类
建包cn.itcast.chapter05.session.example02,编写user有username与password两个属性以及getter和setter方法
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUername(String username) {
this.username=username;
}
public String getPassword() {
return password;
}
public void getPassword(String password) {
this.password=password;
}
第七次 JSP技术
Jsp技术
jsp运行原理:客户端请求jsp容器——里面jsp文件转换Servlet文件(java),在编译class文件(class)后面执行Servlet实例——后面再响应到客户端
jsp基本语法:1.jsp Scriptlets局部变量分配内存空间,调用结束后,释放局部变量占有的内存空间
<% java代码(变量,方法,表达式等)%>
2.jsp声明语句:<%! 变量或方法 %>
<%!
int a=1;
int b=2;
%>
<%!
public String dashuju(){
String str="dashuju2004";
return str;
}
%>
jsp指令:page指令<%@ page 属性.....%> import,language,session,contentType,isErrorPage,errorPage,pageEnCoding等等
include指令:<%@ include file="被包含的文件地址"%>
jsp隐式对象:out,request,response,config,session,application,page,pageContext,exception
out对象:写入数据相当于将数据插入到JspWriter对象的缓冲区,只能调用ServletResponse.getWriter()方法
<%
out.println("first line");
%>
<br/>
<%
response.getWriter().print("second line <br/>");
%>
pageContext对象:
pageContext.PAGE_SCOPE:表示页面范围
pageContext.REQUEST_SCOPE:表示请求范围
pageContext.SESSION_SCOPE:表示会话范围
pageContext.APPLICATION_SCOPE:表示Web应用程序范围
第八次 javabean
JavaBean作用是封装数据。 书写JavaBean需要满足五个规范:
1.这个java类,被public修饰
2.这个java类要提供公共的无参数的构造方法
3.要提供私有的属性
4.要给私有的属性提供公共的set或者get方法
5.要实现Serializable接口
访问JavaBean的属性:
类的成员变量和属性的一个关系:
在普通的java类里面,成员变量可以说成就是属性。
在JavaBean里面,成员变量和属性就有了区别。
在JavaBean 里面成员变量 比如:private String id; 那么id就是成员变量
在JavaBean 里面属性就是get或者set后面的字段名称(字段名称的首字母小写),就是属性。
BeanUtils 工具
BeanUtils 工具是由apache软件基金会提供的一套封装数据到JavaBean的工具类,使用简单方便,
BeanUtils是第三方的工具(插件),所以需要导入jar包。
常用的api:
1.向javaBean的属性设置值:
setProperty(javaBean对象,javaBean的属性,javaBean属性的值);
2.获取javaBean属性的值:
getProperty(javaBean对象,javaBean的属性);
3.向javaBean的属性设置值:
populate(javaBean对象,map对象);
EL表达式
第九次 el表达式
EL表达式中的标识符
在el书写过程中,会用一些符号来标记变量、函数名等,这些符号称之为标识符。
书写规范:
1.不能以数字开头
2.不能包含el中的关键字:and , or 等
3.不能使用el表达式的隐式对象。
4.不能包含特殊符号,比如正斜杠等
1.3 EL中的变量
基本格式:${域对象的名称},这个域对象的名称可以理解为就是el中的变量,
那这个变量就不需要定义了,可以直接使用。
1.4 EL 中的常量
1.布尔常量:true或false
2.数字常量:整型、浮点常量,使用方式和java差不多
3.字符串常量:使用方式和java差不多,比如:${"el的字符串常量"}
4.Null常量:${null}
1.5 EL中的运算符
1.点运算符:获取域对象中属性的值。
比如: ${person.name }
2.方括号运算符:在域对象里,有的属性包含特殊字符,所以用方括号的方式来获取值
比如:<%
Map<String,String> map= new HashMap<String,String>();
map.put("my-name","map的值");
request.setAttribute("user",map);
%>
${user["my-name"] }
3.算术运算符:+ — * /
4.比较运算符: > < >= <= == !=
5.逻辑运算符: &&(and) ||(or) !(not)
6.empty 运算符:用来判断域对象中的值是否存在,不存在返回为true,否则返回的结果是false.
7.三目运算符:参照java的用法。
1.6 EL 隐式对象
1.pageContext对象:为了获取jsp中的隐式对象。
比如:
获取项目的路径:${pageContext.request.contextPath }<br/>
获取请求的URL:${pageContext.request.requestURI }
2.web域相关的对象
域作用范围从小到大:pageContext--->request--->session--->application(servletContext)
el表达式获取域对象中的值:如果域对象的名称相同,获取的是域作用范围最小的值。
和pageContext对象的findAttribute方法的效果是一样的。
${requestScope.指定对象}<br/>
3.param 和 paramValues 对象: 获取表单提交的数据。
比如:
num1:<input type="text" name="num1" /><br/>
num2:<input type="text" name="num" /><br/>
num3:<input type="text" name="num" /><br/>
<input type="submit" value="提交" /> <input type="reset" value="重填" />
<hr/>
num1:${param.num1 }<br/>
num2:${paramValues.num[0] }<br/>
num3:${paramValues.num[1] }
4. Cookie 对象:获取cookie的名称,获取cookie的值
比如:
<% response.addCookie(new Cookie("userName","itcast")); %>
获取cookie对象:${cookie.userName }<br/>
获取cookie的名称:${cookie.userName.name }<br/>
获取cookie的值:${cookie.userName.value }<br/>
3.JSTL
1.1 什么是JSTL
JSTL: JavaServer Pages Standard Tag Libary,java服务器端页面的标准标签库,其实就是在jsp页面上使用的标签库。
JSTL标签库有五个组成,通常使用核心标签库。
在jsp页面上面引入标签库:<%@ taglib uri="标签库的url地址" prefix="标签的前缀" %>
第十次 JSTL
1.2 JSTL中的Core标签
1.<c:out>标签:向网页输出内容
基本语法:
第一种:<c:out value="el表达式获取值" default="值" escapeXml="true或者false"></c:out>
第二种:<c:out value="el表达式获取值" escapeXml="true或者false"> 默认值 </c:out>
escapeXml(默认值true):如果值为true,就会把html标记当成普通的字符串输出,如果值为false,就会正常解析html标记,正常输出。
2.<c:if>标签:进行条件判断,和java类中的if很相似 <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*">
基本语法:
第一种:<c:if test="条件表达式" var="变量名称" scope="域的范围"></c:if>
第二种:<c:if test="条件表达式" var="变量名称" scope="域的范围"> 标签体内容 </c:if>
在开发中,经常使用第二种。
test属性:如果返回值为true,就输出标签体内容,否则就不输出。
3.<c:choose>标签:进行条件判断,和java类中的if,else if(),else if()---else很相似
基本语法:
<c:choose>---->if
<c:when test="条件表达式">标签体内容</c:when>---->else if()
<c:when test="条件表达式">标签体内容</c:when>
------------
<c:otherwise>标签体内容</c:otherwise>----->else
</c:choose>
第十一次 Listener监听器
什么是监听器?
监听器就是监听某个对象的的状态变化的组件
监听器的相关概念:
事件源:被监听的对象 ----- 三个域对象 request session servletContext
监听器:监听事件源对象 事件源对象的状态的变化都会触发监听器 ----
注册监听器:将监听器与事件源进行绑定
响应行为:监听器监听到事件源的状态变化时 所涉及的功能代码 ---- 程序员编写代码
监听器有哪些?
第一维度:按照被监听的对象划分:ServletRequest域 HttpSession域 ServletContext域
第二维度:监听的内容分:监听域对象的创建与销毁的 监听域对象的属性变化的
1.2 监听三大域对象的创建与销毁的监听器
监听ServletContext域的创建与销毁的监听器ServletContextListener
1)Servlet域的生命周期
何时创建:服务器启动创建
何时销毁:服务器关闭销毁
2)监听器的编写步骤(重点):
a)编写一个监听器类去实现监听器接口
b)覆盖监听器的方法
c)需要在web.xml中进行配置---注册
3)监听的方法:
4)配置文件
5)ServletContextListener监听器的主要作用
初始化的工作:初始化对象 初始化数据 ---- 加载数据库驱动 连接池的初始 化
加载一些初始化的配置文件 --- spring的配置文件
任务调度----定时器----Timer/TimerTask
任务调度:
监听Httpsession域的创建于销毁的监听器HttpSessionListener
HttpSession对象的生命周期
何时创建:第一次调用request.getSession时创建
何时销毁:服务器关闭销毁 session过期 手动销毁
HttpSessionListener的方法
监听ServletRequest域创建与销毁的监听器ServletRequestListener
ServletRequest的生命周期
创建:每一次请求都会创建request
销毁:请求结束
ServletRequestListener的方法
1.3监听三大域对象的属性变化的监听器
域对象的通用的方法:
setAttribute(name,value)
--- 触发添加属性的监听器的方法
--- 触发修改属性的监听器的方法
getAttribute(name)
removeAttribute(name)
--- 触发删除属性的监听器的方法
ServletContextAttibuteListener监听器
HttpSessionAttributeListener监听器(同上)
ServletRequestAriibuteListenr监听器(同上)
1.4 与session中的绑定的对象相关的监听器(对象感知监听器)
即将要被绑定到session中的对象有几种状态
绑定状态:就一个对象被放到session域中
解绑状态:就是这个对象从session域中移除了
钝化状态:是将session内存中的对象持久化(序列化)到磁盘
活化状态:就是将磁盘上的对象再次恢复到session内存中
面试题:当用户很对时,怎样对服务器进行优化?
绑定与解绑的监听器HttpSessionBindingListener
钝化与活化的监听器HttpSessionActivationListener
可以通过配置文件 指定对象钝化时间 --- 对象多长时间不用被钝化
在META-INF下创建一个context.xml
<Context>
<!-- maxIdleSwap:session中的对象多长时间不使用就钝化 -->
<!-- directory:钝化后的对象的文件写到磁盘的哪个目录下 配置钝化的对象文件在 work/catalina/localhost/钝化文件 -->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="igeekhome" />
</Manager>
</Context>
被钝化到work/catalina/localhost/的文件
实现监听:
- 创建类实现监听器接口
web.xml
文件中配置(注册)监听器<listener> <listener-class>url</listener-class></listener>
,Servlet3.0
后可以通过注解@WebListener 注册监听器
一、 Listener监听三个域对象创建与销毁
- 监听ServletContext域对象的创建与销毁:实现ServletContextListener接口。
ServletContext域对象的生命周期:
创建:启动服务器时创建
销毁:关闭服务器或者从服务器移除项目
作用: 利用ServletContextListener监听器在创建ServletContext域对象时完成一些想要初始化的工作或者执行自定义任务调度。
监听ServletRequest域对象的创建与销毁:实现ServletRequestListener接口。
ServletRequest域对象的生命周期:
创建:访问服务器任何资源都会发送请求(ServletRequest)出现,访问.html和.jsp和.servlet都会创建请求。
销毁:服务器已经对该次请求做出了响应。
监听HttpSession域对象的创建与销毁:实现HttpSessionListener接口:
HttpSession域对象的生命周期:
创建:只要调用了getSession()方法就会创建,一次会话只会创建一次,
销毁:1.超时(默认为30分钟)2.非正常关闭,销毁3.正常关闭服务器(序列化)
session的钝化活化的用意:
session中的值可能会很多,并且我们有很长一段时间不会去使用这个内存中的值,那么可以考虑把session中的值存储到硬盘上(钝化),等下一次要使用的时候,从硬盘上提取到内存中(活化)。
设置session在一定时间内钝化:
在Tomcat里面 conf/context.xml中配置:配置后对所有运行在该服务器中的项目生效。
在Tomcat里面conf/Catalina/localhost/context.xml中配置(没有就创建一个context.xml文件):对localhost生效,如localhost:8080/
在自己的web工程项目中的META-INF/context.xml中配置:只对当前的工程项目生效。
配置内容:
maxIdleSwap:设置经过该时间就钝化。
directory:设置钝化后存放的目录,没有就自动创建。
第十二章 JDBC
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,同时,JDBC也是个商标名。
是跟数据库进行连接的时候,用来连接到指定远程数据库标识符。
可以在该URL中指定连接用户名和密码,同时,对于不同的数据库有不同的标示。例如连接一个本地机器上的SQLServer数据库的URL如下:
jdbc:sqlserver://localhost;user=MyUserName;password=*****;
然后建立连接:Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost;user=MyUserName;password=*****;");
JDBC API包含以下主要组件:
1.JDBC Driver(JDBC驱动程序)
2.Connection(连接)
3.Statement(声明)
4.ResultSet(结果集)
下面我们简单的给大家介绍其组件。
JDBC驱动程序
JDBC驱动程序是一组Java类,它们实现JDBC接口以与特定数据库进行交互。几乎所有数据库供应商(如MySQL,Oracle,Microsoft SQL Server)都提供JDBC驱动程序。例如,MySQL提供了一个名为MySQL Connection / J的JDBC驱动程序,它允许您通过标准JDBC API使用MySQL数据库。
有三种类型的JDBC驱动程序,包括JDBC本机API驱动程序,JDBC-net驱动程序和JDBC驱动程序。
JDBC驱动程序是用纯Java编写的。它将JDBC调用转换为特定于MySQL的调用,并将调用直接发送到特定数据库。要使用JDBC驱动程序,您需要在应用程序中包含驱动程序JAR文件。MySQL Connector / J是JDBC驱动程序。
连接
JDBC的第一个也是最重要的组件是Connection对象。在Java应用程序中,首先加载JDBC驱动程序,然后建立与数据库的连接。通过Connection对象,您可以与数据库进行交互,例如,创建一个Statement来对表执行SQL查询。您可以一次打开多个数据库连接。
声明
要执行SQL查询,例如SELECT,INSERT,UPDATE,DELETE等,可以使用Statement对象。您可以通过Connection对象创建Statement 对象。JDBC提供了几种类型的不同用途,如语句PreparedStatement,CallableStatement 。
结果集
从数据库查询数据后,您将获得一个ResultSet对象。该ResultSet对象提供了一组API,允许您遍历查询结果。
使用JDBC的典型流程如下:
1.首先,加载JDBC驱动程序并创建与数据库的连接。
2.然后,创建Statement并执行查询以获取ResultSet。
3.接下来,遍历并处理ResultSet。
4.关闭ResultSet,Statement和Connection。
/**
*使用JDBC完成数据的增删改查
*创建JavaBean,创建一个用于保存用户数据User类
*
*代码如下:
**/
package cn.itcast.jdbc.example.domain;
import java.util.Date;
public class User {
private int id;
private String username;
private String password;
private String email;
private Date birthday;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
创建工具类
每次操作数据库都需要加载驱动,建立数据库连接以及关闭数据库连接,为避免代码重复书写,专门建立一个数据库相关操作的工具类
代码如下:
package cn.itcast.jdbc.example.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCUtils {
// 加载驱动,并建立数据库连接
public static Connection getConnection() throws SQLException,
ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/jdbc";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, username,
password);
return conn;
}
// 关闭数据库连接,释放资源
public static void release(Statement stmt, Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
public static void release(ResultSet rs, Statement stmt,
Connection conn){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
release(stmt, conn);
}
}
创建Dao
创建UersDao的类,封装对表users的添加、查询、删除和更新等操作
代码如下:
package cn.itcast.jdbc.example.dao;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import cn.itcast.jdbc.example.domain.User;
import cn.itcast.jdbc.example.utils.JDBCUtils;
public class UsersDao {
// 添加用户的操作
public boolean insert(User user) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 获得数据的连接
conn = JDBCUtils.getConnection();
// 获得Statement对象
stmt = conn.createStatement();
// 发送SQL语句
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(user.getBirthday());
String sql = "INSERT INTO users(id,name,password,email,birthday) "+
"VALUES("
+ user.getId()
+ ",'"
+ user.getUsername()
+ "','"
+ user.getPassword()
+ "','"
+ user.getEmail()
+ "','"
+ birthday + "')";
int num = stmt.executeUpdate(sql);
if (num > 0) {
return true;
}
return false;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, stmt, conn);
}
return false;
}
// 查询所有的User对象
public ArrayList<User> findAll() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
ArrayList<User> list = new ArrayList<User>();
try {
// 获得数据的连接
conn = JDBCUtils.getConnection();
// 获得Statement对象
stmt = conn.createStatement();
// 发送SQL语句
String sql = "SELECT * FROM users";
rs = stmt.executeQuery(sql);
// 处理结果集
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("name"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
list.add(user);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, stmt, conn);
}
return null;
}
// 根据id查找指定的user
public User find(int id) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 获得数据的连接
conn = JDBCUtils.getConnection();
// 获得Statement对象
stmt = conn.createStatement();
// 发送SQL语句
String sql = "SELECT * FROM users WHERE id=" + id;
rs = stmt.executeQuery(sql);
// 处理结果集
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("name"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
return user;
}
return null;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, stmt, conn);
}
return null;
}
// 删除用户
public boolean delete(int id) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 获得数据的连接
conn = JDBCUtils.getConnection();
// 获得Statement对象
stmt = conn.createStatement();
// 发送SQL语句
String sql = "DELETE FROM users WHERE id=" + id;
int num = stmt.executeUpdate(sql);
if (num > 0) {
return true;
}
return false;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, stmt, conn);
}
return false;
}
// 修改用户
public boolean update(User user) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 获得数据的连接
conn = JDBCUtils.getConnection();
// 获得Statement对象
stmt = conn.createStatement();
// 发送SQL语句
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String birthday = sdf.format(user.getBirthday());
String sql = "UPDATE users set name='" + user.getUsername()
+ "',password='" + user.getPassword() + "',email='"
+ user.getEmail() + "',birthday='" + birthday
+ "' WHERE id=" + user.getId();
int num = stmt.executeUpdate(sql);
if (num > 0) {
return true;
}
return false;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(rs, stmt, conn);
}
return false;
}
}
第十三次 数据库连接池与DBUtils工具
在JDBC编程中,每次创建和断开Connection对象都会消耗一定的时间和IO资源。这是因为在Java程序与数据库之间建立连接时,数据库端要验证用户名和密码,并且要为这个连接分配资源,Java程序则要把代表连接的java.sql.Connection对象等加载到内存中,所以建立数据库连接的开销很大,尤其是在大量的并发访问时。假如某网站一天的访问量是10万,那么,该网站的服务器就需要创建、断开连接10万次,频繁地创建、断开数据库连接势必会影响数据库的访问效率,甚至导致数据库崩溃。为了避免频繁地建数据库连接,数据库连接池技术应运而生。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用现有的数据库连接,而不是重新建立。
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,当应用程序访问数据库时并不是直接创建Connection, 而是向连接池“申请”一个Connection。如果连接池中有空闲的Connection,则将其返回,否则创建新的Connection。使用完毕后,连接池会将该Connection回收,并交付其他的线程使用,以减少创建和断开数据库连接的次数,提高数据库的访问效率。
在Java中开源的数据库连接池有以下几种 :
1、C3P0:是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate [2] 一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。
2、Proxool:是一个Java SQL Driver驱动程序,提供了对选择的其它类型的驱动程序的连接池封装。可以非常简单的移植到现存的代码中,完全可配置,快速、成熟、健壮。可以透明地为现存的JDBC驱动程序增加连接池功能。
3、Jakarta DBCP:DBCP是一个依赖Jakartacommons-pool对象池机制的数据库连接池。DBCP可以直接的在应用程序中使用。
4、DDConnectionBroker:是一个简单、轻量级的数据库连接池。
5、DBPool:是一个高效、易配置的数据库连接池。它除了支持连接池应有的功能之外,还包括了一个对象池,使用户能够开发一个满足自己需求的数据库连接池。
6、XAPool:是一个XA数据库连接池。它实现了javax.sql.XADataSource并提供了连接池工具。
7、Primrose:是一个Java开发的数据库连接池。当前支持的容器包括Tomcat4&5、Resin3与JBoss3。它同样也有一个独立的版本,可以在应用程序中使用而不必运行在容器中。Primrose通过一个WEB接口来控制SQL处理的追踪、配置,以及动态池管理。在重负荷的情况下可进行连接请求队列处理。
8、SmartPool:是一个连接池组件,它模仿应用服务器对象池的特性。SmartPool能够解决一些临界问题如连接泄漏(connection leaks)、连接阻塞、打开的JDBC对象(如Statements、PreparedStatements)等。SmartPool的特性包括:
-
支持多个pool
-
自动关闭相关联的JDBC对象
-
在所设定time-outs之后察觉连接泄漏
-
追踪连接使用情况
-
强制启用最近最少用到的连接
-
把SmartPool“包装”成现存的一个pool
9、MiniConnectionPoolManager:是一个轻量级JDBC数据库连接池。它只需要Java1.5(或更高)并且没有依赖第三方包。
10、BoneCP:是一个快速、开源的数据库连接池。帮用户管理数据连接,让应用程序能更快速地访问数据库。比C3P0/DBCP连接池速度快25倍。
11、Druid:Druid不仅是一个数据库连接池,还包含一个ProxyDriver、一系列内置的JDBC组件库、一个SQL Parser。
支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等。
Druid针对Oracle和MySql做了特别优化,比如:
-
Oracle的PS Cache内存占用优化
-
MySql的ping检测优化
Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。
简单SQL语句用时10微秒以内,复杂SQL用时30微秒。
通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter,就是通过Druid的SQL Parser分析语义实现的
为了获取数据库连接对象,JDBC提供了javax.sql.DataSource接口,它负责与数据库建立连接,并定义了返回值为Connection对象的方法,具体如下:
1.Connection getConnection()
2.Connection getConnection(String username,String password)
上述两个重载的方法都能用来获取Connection对象。不同的是,第1个方法是通过无参的方式建立与数据库的连接,第2个方法是通过传入登录信息的方式建立于数据库的连接
接口通常都会有其实现类,javax.sql.DataSource接口也不例外,通常习惯性地把实现了javax.sql.DataSource接口的类称为数据源,顾名思义,数据源即数据的来源。在数据源中存储了所有建立数据库的连接信息。就像通过指定文件名称可以在文件系统中找到文件一样,也可以找到相应的数据库连接
数据源包含数据库连接池。如果数据是水,数据库就是水库,数据源就是连接到水库的管道,终端用户看到的数据集是管道里流出来的水。一些开源组织提供了数据源的独立实现,常用的有DBCP数据源和C3P0数据源
DBCP数据源:
是数据库连接池的简称,是Apache组织下的开源连接池的实现,也是Tomcat服务器使用的连接池组件。单独使用DBCP数据源时,需要在应用程序中导入两个JAR包。
数据源对象的创建:
通过 BasicDataSource 类直接创建数据源对象
在使用 BasicDataSource类创建一个数据源对象时,需要手动给数据源对象设置属性值,然后获取数据库连接对象。接下来,通过一个案例来演示BasicDataSource类的使用,具体步骤如下。
(1).导入包
通过读取配置文件创建数据源对象
除了使用 BasicDatasource自接创建数据源对象外,还可以使用BasicDataSourceFactory
工厂类读取配置文件,创建数据源对象,然后获取数据库连接对象。
创建一个Example02类,该类中采用了从配量文件中获取数据库的连接信息和数据源的初始化信息的方法
第十四次JSP开发模型
单纯的JSP编程
在 JSP 编程模式下,通过应用 JSP 中的脚本标志,可以直接在 JSP 页面中实现各种功能。虽然这种模式很容易实现,但是,其缺点也非常明显。因为将大部分的 Java 代码与 HTML 代码混淆在一起,会给程序的维护和调试带来很多困难,而且难以理清完整的程序结构。
这就好比规划管理一个大型企业,如果将负责不同任务的所有员工都安排在一起工作,势必会造成公司秩序混乱、不易管理等许多隐患。所以说,单纯的 JSP 页面编程模式是无法应用到大型、中型甚至小型的 JSP Web 应用程序开发中的。
JSP+JavaBean 编程
JSP+JavaBean 编程模式是 JSP 程序开发经典设计模式之一,适合小型或中型网站的开发。利用 JavaBean 技术,可以很容易地完成一些业务逻辑上的操作,例如数据库的连接、用户登录与注销等。
JavaBean 是一个遵循了一定规则的 Java 类,在程序的开发中,将要进行的业务逻辑封装到这个类中,在 JSP 页面中,通过动作标签来调用这个类,从而执行这个业务逻辑。此时的 JSP 除了负责部分流程的控制外,主要用来进行页面的显示,而 JavaBean 则负责业务逻辑的处理。
可以看出,JSP+JavaBean 设计模式具有一个比较清晰的程序结构,在 JSP 技术的起步阶段,该模式曾被广泛应用。
图 1 表示该模式对客户端的请求进行处理的过程,相关的说明如下。
- 用户通过客户端浏览器请求服务器。
- 服务器接收用户请求后调用 JSP 页面。
- 在 JSP 页面中调用 JavaBean。
- 在 JavaBean 中连接及操作数据库,或实现其他业务逻辑。
- JavaBean 将执行的结果返回 JSP+ 页面。
- 服务器读取 JSP 页面中的内容(将页面中的静态内容与动态内容相结合)。
- 服务器将最终的结果返回给客户端浏览器进行显示。
JSP+JavaBean+Servlet 编程
JSP+JavaBean 设计模式虽然已经对网站的业务逻辑和显示页面进行了分离,但这种模式下的 JSP 不但要控制程序中的大部分流程,而且还要负责页面的显示,所以仍然不是一种理想的设计模式。
在 JSP+JavaBean 设计模式的基础上加入 Servlet 来实现程序中的控制层,是一个很好的选择。在这种模式中,由 Servlet 来执行业务逻辑并负责程序的流程控制,JavaBean 组件实现业务逻辑,充当模型的角色,JSP 用于页面的显示。可以看出,这种模式使得程序中的层次关系更明显,各组件的分工也非常明确。图 2 表示该模式对客户端的请求进行处理的过程。
图 2 所示的模式中,各步骤的说明如下。
- 用户通过客户端浏览器请求服务器。
- 服务器接收用户请求后调用 Servlet。
- Servlet 根据用户请求调用 JavaBean 处理业务。
- 在 JavaBean 中连接及操作数据库,或实现其他业务逻辑。
- JavaBean 将结果返回 Servlet,在 Servlet 中将结果保存到请求对象中。
- 由 Servlet 转发请求到 JSP 页面。
- 服务器读取 JSP 页面中的内容(将页面中的静态内容与动态内容结合)。
- 服务器将最终的结果返回给客户端浏览器进行显示。
但 JSP+JavaBean+Servlet 模式同样也存在缺点。该模式遵循了 MVC 设计模式,MVC 只是一个抽象的设计概念,它将待开发的应用程序分解为三个独立的部分:模型(Model)、视图(View)和控制器(Controller)。
虽然用来实现 MVC 设计模式的技术可能都是相同的,但各公司都有自己的 MVC 架构。也就是说,这些公司用来实现自己的 MVC 架构所应用的技术可能都是 JSP、Servlet 与 JavaBean,但它们的流程及设计却是不同的,所以工程师需要花更多的时间去了解。
从项目开发的观点上来说,因为需要设计 MVC 各对象之间的数据交换格式与方法,所以在系统的设计上需要花费更多的时间。
使用 JSP+JavaBean+Servlet 模式进行项目开发时,可以选择一个实现了 MVC 模式的现成的框架,在此框架的基础上进行开发,能够大大节省开发时间,会取得事半功倍的效果。目前,已有很多可以使用的现成的 MVC 框架,例如 Struts 框架。
MVC 模式
MVC(Model-View-Controller,模型-视图-控制器)是一种程序设计概念,它同时适用于简单的和复杂的程序。使用该模式,可将待开发的应用程序分解为三个独立的部分:模型、视图和控制器。
提出这种设计模式主要是因为应用程序中用来完成任务的代码(模型,也称为“业务逻辑”)通常是程序中相对稳定的部分,并且会被重复使用,而程序与用户进行交互的页面(视图),却是经常改变的。
如果因需要更新页面而不得不对业务逻辑代码进行改动,或者要在不同的模块中应用相同的功能时重复地编写业务逻辑代码,不仅会降低整体程序开发的进程,而且会使程序变得难以维护。因此,将业务逻辑代码与外观呈现分离,将会更容易地根据需求的改变来改进程序。
Model(模型):MVC 模式中的 Model(模型)指的是业务逻辑的代码,是应用程序中真正用来完成任务的部分。
View(视图):视图实际上就是程序与用户进行交互的界面,用户可以看到它的存在。视图可以具备一定的功能,并应遵守对其所做的约束。在视图中,不应包含对数据处理的代码,即业务逻辑代码。
Controller(控制器):控制器主要用于控制用户请求并做出响应。它根据用户的请求,选择模型或修改模型,并决定返回什么样的视图。
第十五次 文件的上传下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能。
对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,struts上传的功能就是基于这个实现的。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。
图15.1 文件的上传逻辑流程图
具体的代码实现
1.基础环境的搭建
创建一个FileUploadAndDownLoad项目,加入Apache的commons-fileupload文件上传组件的相关Jar包,如下图所示:
2.实现上传与下载
2.1文件上传页面和消息提示页面
upload.jsp页面的代码如下:
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post">
上传用户:<input type="text" name="username"><br/>
上传文件1:<input type="file" name="file1"><br/>
上传文件2:<input type="file" name="file2"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
message.jsp的代码如下:
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>消息提示</title>
</head>
<body>
${message}
</body>
</html>
2.2处理文件的servlet
<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>消息提示</title>
</head>
<body>
${message}
</body>
</html>
UploadHandleServlet的代码如下:
package me.gacl.web.controller;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
public class UploadHandleServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
File file = new File(savePath);
//判断上传文件的保存目录是否存在
if (!file.exists() && !file.isDirectory()) {
System.out.println(savePath+"目录不存在,需要创建");
//创建目录
file.mkdir();
}
//消息提示
String message = "";
try{
//使用Apache文件上传组件处理文件上传步骤:
//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解决上传文件名的中文乱码
upload.setHeaderEncoding("UTF-8");
//3、判断提交上来的数据是否是上传表单的数据
if(!ServletFileUpload.isMultipartContent(request)){
//按照传统方式获取数据
return;
}
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> list = upload.parseRequest(request);
for(FileItem item : list){
//如果fileitem中封装的是普通输入项的数据
if(item.isFormField()){
String name = item.getFieldName();
//解决普通输入项的数据的中文乱码问题
String value = item.getString("UTF-8");
//value = new String(value.getBytes("iso8859-1"),"UTF-8");
System.out.println(name + "=" + value);
}else{//如果fileitem中封装的是上传文件
//得到上传的文件名称,
String filename = item.getName();
System.out.println(filename);
if(filename==null || filename.trim().equals("")){
continue;
}
//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
//处理获取到的上传文件的文件名的路径部分,只保留文件名部分
filename = filename.substring(filename.lastIndexOf("\\")+1);
//获取item中的上传文件的输入流
InputStream in = item.getInputStream();
//创建一个文件输出流
FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);
//创建一个缓冲区
byte buffer[] = new byte[1024];
//判断输入流中的数据是否已经读完的标识
int len = 0;
//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
while((len=in.read(buffer))>0){
//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
out.write(buffer, 0, len);
}
//关闭输入流
in.close();
//关闭输出流
out.close();
//删除处理文件上传时生成的临时文件
item.delete();
message = "文件上传成功!";
}
}
}catch (Exception e) {
message= "文件上传失败!";
e.printStackTrace();
}
request.setAttribute("message",message);
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在Web.xml文件中注册UploadHandleServlet:
<servlet>
<servlet-name>UploadHandleServlet</servlet-name>
<servlet-class>me.gacl.web.controller.UploadHandleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadHandleServlet</servlet-name>
<url-pattern>/servlet/UploadHandleServlet</url-pattern>
</servlet-mapping>