servlet再学习

1、servlet里面的mvc说的是m是逻辑处理,c是处理请求的走向,v是进行表示,真正的mvc中m根本不知道有v的存在,让m成为一个具有独立功能的类

2、servlet的转发和重定向
(1)转发:转发对于浏览器是透明的,浏览器并不知道后台对请求进行了转发,所以浏览器的url不变,有2个方式获得转发对象RequestDiapatcher(顾名思义,转发对象就是用来转发):一种是通过HttpServletRequest的getRequestDispatcher("绝对相对路径都可以"),一种是通过ServletCountext的getRequestDispatcher("只能写绝对路径,以/开头",
获得转发对象就可以把请求响应对象也转发过去RequestDispatcher.forward(req,resp);
怎么把java中的属性带到jsp中去呢?
答:req.setAttribute("键名",值),然后在jsp中的scriptlet代码块中HttpServletRequest.getParameter("键名"),jsp中自带有3个对象,分别是HttpServletRequest,HttpServletResponse,PrintWriter

(2)重定向:HttpServletResponse.sendRedirect("目的地")
可以重定向到任意url,但是不能共享request范围内的数据,浏览器的地址栏改变

3、
接受单个参数:request.getParameter("参数名")
多个参数:request.getParameterValues("参数名")

4、怎么下载?
首先要有2个流,一个InputStream,一个OutpotStream,一个中间承接的byte数组
InputStream 可以是读取项目内的文件的,也可以是读取绝对路径中的任何文件,如果是读取项目内的文件的:InputStream is =ServletCoutext.getResourAsStream("/文件名")
读取项目外的:InputStream is=new FileInputStream("/文件绝对路径")

while((read=is.read(bytes))!=-1){
os.write(bytes,0,read);
}
os.flush();
os.close();

OutputStream os= resp.getOutputStream(),OutputStream由响应对象提供

如过没有加上这一句就会变成打开文件而不是下载:
resp.setContentType("application/jpeg");

5、如何使用ServletContext来制造一个面对所有servlet都可以共享的对象?
(1)创建一个继承ServletContextListener的类,那么这个类就成为了监听ServletContext生成和销毁的监听器
(2)web.xml需要添加Listener声明
<listener>
<listener-class>Listener.ListenerTest</listener-class>
</listener>
为什么只声明listener容器就知道这是一个servletContext的监听器呢?
答:容器回去检查这个Listener是实现了哪个接口,以此确定他是哪种类型的监听器
(3)在监听器中:
使用:ServletContext servletContext=servletContextEvent.getServletContext();获取ServletContext对象,使用ServletContext.setAttribute();设置键值对
(4)在servlet中,使用getServletContext()获取ServletContext对象,使用ServletContext.getAttribute()获取所需对象,此处所获取的对象是Object类型的,按照所需进行转化,ServletContext中所保存的对象是所有servlet共享的

6、servletContext的getInitParameter()获取初始化参数,需要在web.xml添加Context-param声明
servletContext的getAttribute()获取键值对,也可以设置,然后在另一个servlet中获取

7、因为上下文不是线程安全的,多个servlet可以同时对servlet中属性进行修改,这就可能导致不安全,可以在可能会导致线程不安全的地方添加同步快
synchronized(getServletContext()){}。直接用ServletContext对象本身作为锁就可以实现线程安全

8、HttpServletRequest和HttpServletResponse各自的api
(1)HttpServletRequest
getCookies() 返回一个Cookie[]
getMethod()返回请求方法
getSession() 得到HttpSession
getRequestSessionId()得到SessionId
setAttribute(String,Object)设置属性
getAttribute(String)获得属性
removeAttribute(String)删除属性
getParameter(String)获得请求中夹带的参数
getParameterValues(String)获得1个参数的多个值,例如多选框

(2)HttpServletResponse
addCookie(Cookie)为响应对象添加cookie,最终这个cookie会保存到这个当前响应的客户端
sendredirect(String)重定向
setStatus(int)设置状态码
setError(int,String) 人为的设置错误状态码,以及添加错误描述
setContentType(String)设置相应的文件类型,浏览器根据这个来决定如何处理这个响应
setCharacterEncoding(String)设置编码
getWriter()获得面向浏览器的写入流

9、cookie和Session
cookie是保存在浏览器的,session保存在服务器,
(1)cookie是由服务端创建,并添加到响应中,返回给浏览器,浏览器下次发送请求就会把该cookie连同请求一个发送给服务器,服务端检查cookie就用户的信息
cookie的属性除了name,value之外,maxAge是控制cookie存在时间,单位为秒,0是表示删除cookie,-1是默认的,关闭浏览器则失效
cookie的修改只能是覆盖,删除只能通过setMaxAge(-1)设置
在对cookie数组进行遍历前,要先判断cookie数组存不存在

(2)session是客户端第一次请求服务器时创建的
request还可以使用getSession(boolean create)来获取Session。区别是如果该客户的Session不存在
Session机制决定了当前客户只会获取到自己的Session,而不会获取到别人的Session。各客户的Session也彼此独立,互不可见。
session保存在内存里,session的超时属性是maxInactiveInterval,单位是秒
setAttribute(String,Object)设置session,removeAttribute(String)移除session
isNow()返回该session是否是新创建的,invalidate()使该session失效
session默认超时时间是20分钟

10、URL地址重写是对客户端不支持Cookie的解决方案,先不学习

11、jsp中的隐式对象
JspWriter Out
HttpServletRequest request
HttpServletResponse response
HttpSession session
ServletContext application
ServletConfig config
Throwable exception
PageContext PageContext
object page

12、servlet的监听器
(1)ServletContextAttributeListener 监听对ServletContext属性的操作
(2)ServletContextListener 监听context的初始化和销毁
(3)ServletRequestListener和ServletRequestAttributeListener监听request初始化,reques属性的增加,删除等
(4)HttpSessionListener 监听session的创建和销毁

13、 servlet过滤器
servlet的过滤器是和监听器类似,都是为servlet服务的,Filter也需要在DD中部署
一个普通的类实现了Filter接口,就变成一个过滤器,实心Filter接口需要实现3个方法
init():通常用来保存config对象
doFilter()做具体的工作,并进行跳转FilterChain.doFilter(req,resp)
destroy()空实现

在DD中怎么声明?
需要先声明过滤器:<filter>--<filter-name>--<filter-class>
声明映射:<filter-mapping>--<filter-name>--<url-pattern>(<servlet-name>)
如果一个url匹配多个过滤器,则按照在DD中的声明顺序进行过滤

如何实现压缩响应?
要实现压缩响应,可以在请求流经过滤器的时候,把响应对象更改为你自己的定制响应对象,分为2步:
(1)首先你要自己定制一个响应包装类
class CompressionResponseWrapper extends HttpServletResponseWrapper{
//覆盖定制方法
}
(2)在过滤器中创建一个包装类对象
CompressionResponseWrapper wr=new CompressionResponseWrapper(response);
把response替换成wr:chain.doFilter(req,wr);

14、设置错误页面
可以设置指定状态码和指定异常的servlet
在DD中,先声明一个servlet,再声明错误页面:
<error-page>-- 状态码<error-code>--映射的servlet的url<location>
<error-page>--触发的异常<exception-type>--映射的servlet的url<location>

15、idea怎么导入jar包
在项目结构窗口,modules(单元项),点+号就可以添加jar包

16、servlet怎么跟数据库交互,完整例子

import java.sql.*;

/**
* Created by shenzhi on 2017/10/21.
*/
public class MysqlTest {


static final String JDBC_DRIVER="com.mysql.jdbc.Driver";
static final String DB_URL="jdbc:mysql://localhost:3306/shen_db";

static final String USER="root";
static final String PASS="123456";

public static void main(String[] args){

Connection conn=null;
Statement stmt=null;

try{
//注册JDBC驱动
Class.forName("com.mysql.jdbc.Driver");

//打开链接
System.out.println("打开链接");
conn= DriverManager.getConnection(DB_URL,USER,PASS);

//执行查询
System.out.println("实例化Statement");
stmt=conn.createStatement();
String sql="select * from persons";

ResultSet rs=stmt.executeQuery(sql);

while(rs.next()){
System.out.println(rs.getString("city"));
}

rs.close();
stmt.close();
conn.close();


}catch(SQLException se){
se.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(conn!=null)conn.close();
}catch(SQLException se){
///什么都不做
}

try{
if(stmt!=null)stmt.close();
}catch(SQLException se){
//什么都不做
}
System.out.println("再见");
}
}
}

17、插入学习java的Class类,和reflection(反射)类
了解类的底层是类如何运作的

Class.forName("类名");会返回一个Class对象,这个Class对象是:
与带有给定字符串名的类或接口相关联的 Class 对象,就是说这个Class对象与参数里的那个类有关系
有什么用呢?
如果给你一个不是你写的类,你说如何知道这个类中的:成员变量,构造函数,函数等信息的?一种方式是看源代码,另一种方式就是利用反射,反射也是另一种不使用new创建新对象的方式:Dog dog=Class.forName("Dog").newInstance();
获得运行时类后,可以获得的信息有哪些呢?
getName():String
getSuperClass():Class
getInterfaces():Class[]
isArray():boolean
isEnum():boolean
isInterface():boolean
isPrimitive():boolean


获得运行时类有3中方法
(1)类名.class
(2)Class.forName("类名");
(3)实例名.getClass();

new Classname()这种属于静态加载
Class.forName()属于动态加载
2中加载的区别就是静态加载的类在编译时就需要提供,动态加载的类的源程序可以在编译时缺席,在运行时按需提供

Class.forName()的作用是要求jvm查找并加载指定的类,所以该类的无参构造器和静态代码段会被执行,也就是说如果你这个类拥有有参数的构造器,那么你就得显式的声明无参构造函数

//在jdk6中,其实是可以不用调用Class.forName来加载mysql驱动的,因为mysql的驱动程序jar包中已经包含了java.sql.Driver配置文件,在文件中添加了com.mysql.jdbc.Driver.但在JDK6之前版本,还是要调用这个方法。

这就解释了为什么jdbc(java database connectivity)为什么对驱动进行注册要使用Class.forName("com.mysql.jdbc.Driver");因为调用这句话的时候,就会调用Driver类的static代码块。而里面就会生成一个DriverManager,这个Manager就可以用来取得对数据库的连接(DriverManager.getConnection(url,user,password)),取得连接后,就可以使用这个连接来创建sql语句(conn.createStatement(sql语句)),创建完的statement就可以调用执行查询函数(stmt.executeQuery()),执行这个executeQuery()会返回一个ResultSet,使用rs就可以遍历出表了

18、
connection的api
createStatement():Statement
prepareStatement(String sql):prepareStatement
perpareCall(String sql) :CallableStatement
commit()
rollback()
close()

Statement的api
executeQuery(String sql) :ResultSet
executeQuery(String sql):int
executeUpdate(String sql,String columnNames[] ):int
execute(Srting sql,String columnNames[]):boolean
close()
setAutoCommit(false);关闭自动提交
commit()当自动提交被关闭时需要手动调用commit函数,查询才会被提交
getMaxRows() :int
setFetchSize(int rows)设置查询返回的行数,测试无效
addBatch()把一个statement添加到batch中,一般批处理只会在进行insert into 或update才使用
clearBatch()
executeBatch():int[],执行batch中的所有语句


PreparedStatement extends Statement 的api
pstmt=conn.preparedStatement("select * from shen_db where city=?")设置sql语句时可以先设置为问号?,然后再调用pstmt.setXXX()为该参数赋值
executeQuery():ResultSet
executeUpdate():int
execute():boolean
setInt(int parameterIndex int x)设置参数,第一个参数是在sql语句里的排序,从1开始
setFloat(int parameterIndex,float x)
setString(int parameterIndex,String x)
setTimestamp(int parameterIndex, java.sql.Timestamp x)

 

ResultSet的spi
next():boolean
close();
getString(int columnIndex):String
getBlob(int columnIndex) :Blob blob是一种使用二进制保存的数据
getInt(int column) :int
getDate(int column): Date
isFirst():boolean
isLast():boolean

19、jdbc事务
为什么jdbc事务要先把自动提交关闭?
因为如果是自动提交的话,那么每一个sql都是作为个人执行的事务

要使一些sql语句组成一个事务的话,分为3步:
(1)conn.setAutoCommit(flase):把sql自动提交设置为手动,如果不这样做,程序在执行的时候,执行到哪个语句就直接提交了,就构不成事务了
(2)conn.commit():在各个sql语句啥都执行pstmt.executeUpdate()后,把这些语句作为一个事务提交,只要这其中有报异常,所有的操作都会被回滚
(3)在catch块里面,要对conn进行判断,如果conn存在就进行conn.rollback(),当然,rollback也可能报异常,所以也要包含在try里面
**事务里面还可以添加一些小东西,帮助我们更好的控制事务,比如在一个大事务里面,添加一些保存点,让我们可以以更小的颗粒度控制事务
pstmt.executeUpdate();
SavePoint sp=conn.setSqvePoint();
conn,rollback(sp);
那么保存点sp前的sql操作都会被回滚

20、数据库连接池DBCP
使用数据库连接池需要导入commons-dbcp2.jar,commons-logging.jar,commons-pools.jar3个jar包,缺一不可,如果是连接mysql数据库的话,mysql-connection-java-bin.jar也不不可缺少的

DBCP连接池使用的是BasicDataSource对象,这个对象就是一个连接池,
基本属性
ds.setUrl("URL");
ds.setUsername("USER");
ds.setPassword("password");
连接池高级属性
setInitialSize(int i)设置连接池预备连接,就是创建后就预备好的连接数
setMaxTotal(int i)设置最大连接数,如果连接已满,线程等待
setMaxWaitMillis(int i)设置线程最大等待时间,超过报异常
setMaxIdle(int i);归还连接时如果池里连接大于此数则连接销毁
setMinIdle(int i)空闲连接低于此数,则创建连接

mysql默认关闭空闲时间超过8小时的连接
定期检查
setTestWhileIdle(true)开启定期检查
setMinEvictableIdleTimeMillis()销毁连接最小空闲时间<8小时
setTImeBetweenEvictionRunsMillis()检查运行时间间隔

 

Connection conn=ds.getConnection();租借连接
conn.close();归还连接

 

posted @ 2017-10-25 17:07  神芝  阅读(244)  评论(0编辑  收藏  举报