文章目录
基础
装饰器模式(包装模式)简单来说就是扩展原有类的原有方法,其他详细内容这里不做过多说明
这里用两个案例讲解:
1.目标:扩展数据库连接的close方法,不要关闭连接,要还回池中(模拟连接池)
//java.sql.Connection:被包装类
//自己写的:包装类 MyConnection1
//a、编写包装类,实现与被包装类相同的接口(使他们有相同的行为)
//b、定义一个变量,引用被包装的对象(记住原有对象的信息)
//c、定义包装类的构造方法,传入被包装对象的引用(给b赋值)
//d、对于要改写的方法(比如close),编写你自己的代码即可(功能的扩展)
//e、对于不需要改写的方法,调用原有对象的。
public class MyConnection1 implements Connection {
private Connection conn;//原来的conn,针对所有的驱动
private LinkedList<Connection> pool;//原来的池
public MyConnection1(Connection conn,LinkedList<Connection> pool) {
this.conn = conn;
this.pool = pool;
}
//还回池中
public void close() throws SQLException{
pool.addLast(conn);
}
确认包装的法宝:System.out.println(*.class.getName());打印看看
2.IO流中的装饰器模式
建立BufferedReaderDemo
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
//记住,不能加/
Reader r = new FileReader("src/com/itheima/filter/FilterDemo.java");
BufferedReader br = new BufferedReader(r);
MyBufferedReader mbr = new MyBufferedReader(br);
String str = null;//记录读到的数据
while((str=mbr.readLine())!=null){
System.out.println(str);
}
mbr.close();
}
}
建立MyBufferedReader包装类
//包装五步之一,实现被包装相同的接口
public class MyBufferedReader extends BufferedReader {
private int linenum=1;//行号
//包装五步之二,引用被包装的对象
private BufferedReader br;
//包装五步之三,构造函数传入被包装类的对象
public MyBufferedReader(BufferedReader br){
super(br);
this.br=br;
}
//包装五步之四,改写需要修改的方法
//先拿到原有对象的放回值,然后再做判断后进行包装
public String readLine() throws IOException {
String str = br.readLine();
if(str==null)
return null;
if(linenum<10)
return linenum++ +" "+":"+str;
if(linenum>9&&linenum<100)
return linenum++ +" "+":"+str;
return linenum++ +":"+str;
}
//包装五步之五,不需要改写的方法调用原有对象
}
如果上面的内容理解了,相信下面的例子也能很好理解,接下来讲解Java中的过滤器高级案例,这里应用到了上面的装饰器模式!
过滤器中的装饰器模式
案例一:全站乱码解决(get+post)
建立AllCharacterEncodingFilter
//实现解决全站乱码问题的过滤器
public class AllCharacterEncodingFilter implements Filter {
private String encoding = "UTF-8";//设置默认编码
public void init(FilterConfig filterConfig) throws ServletException {
//获取配置文件中的信息,初始化信息encoding的值
String value = filterConfig.getInitParameter("encoding");
if(value!=null){
encoding = value;
}
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
//必须转成HTTP协议的request类,因为放行后的servlet有可能会使用http协议的方法
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//解决POST请求参数中文编码问题
request.setCharacterEncoding(encoding);
//输出编码及通知客户端编码
response.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
//写一个包装类,对request进行包装,包装类必须把被包装的对象传进来;
MyHttpServletRequest mrequest = new MyHttpServletRequest(request);
chain.doFilter(mrequest, response);
}
public void destroy() {
}
}
class MyHttpServletRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;//引用原有对象
public MyHttpServletRequest(HttpServletRequest request) {
super(request);
this.request=request;
}
//覆盖方法
public String getParameter(String name) {
//获取name的值,后续使用
String value = request.getParameter(name);
if(value==null){
return null;
}
//只解决GET请求参数编码问题 //获取提交方式
String method = request.getMethod();
//因为浏览器提交的方法名大小写不同,所以比较的时候需要忽略大小写
if("get".equalsIgnoreCase(method)){
try {
//Tomcat的默认编码是ISO-8859-1,所以设置编码的时候需要注意
value = new String(value.getBytes("ISO-8859-1"), request.getCharacterEncoding());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return value;
}
}
设置配置文件
<filter>
<filter-name>AllCharacterEncodingFilter</filter-name>
<filter-class>com.itheima.filter.AllCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AllCharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
案例二:脏话过滤器
DirtyWordsFilter(注意要有解决全站乱码的过滤器)
public class DirtyWordsFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest arg1, ServletResponse arg2,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) arg1;
HttpServletResponse response = (HttpServletResponse) arg2;
//对request进行包装,过滤
DwHttpServletRequest dwrequest = new DwHttpServletRequest(request);
chain.doFilter(dwrequest, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
class DwHttpServletRequest extends HttpServletRequestWrapper{
private HttpServletRequest request;
public DwHttpServletRequest(HttpServletRequest request){
super(request);
this.request = request;
}
public String getParameter(String name) {
String value = request.getParameter(name);
if(value==null){
return null;
}//定义脏话字典
String[] dws = new String[]{"畜生","禽兽"};
for(String s:dws){
//判断value里面是否包含脏话字典里的词
if(value.contains(s)){
//
value = value.replace(s, "**");
}
}
return value;
}
}
案例三:全站压缩
注意在进行配置文件设置的时候,只需要设置和文本相关的*.jsp;.html,.js;*.css
public class GzipFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest arg1, ServletResponse arg2,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) arg1;
HttpServletResponse response = (HttpServletResponse) arg2;
GzipHttpServletResponse gresponse = new GzipHttpServletResponse(response);
chain.doFilter(request, gresponse);
//获取原始字节,进行压缩
byte[] b = gresponse.getBufferData();
System.out.println("压缩前的大小:"+b.length);//测试用
//建立一个byte[]输出流,关联到Gzip压缩流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//Gzip流需要一个字节输出流来关联,压缩流内的数据
GZIPOutputStream gos = new GZIPOutputStream(baos);
gos.write(b);
gos.close();
b = baos.toByteArray();//取出缓存中被压缩后的数据
System.out.println("压缩有的大小:"+b.length);
//告知浏览器压缩方式,就是设置头
response.setHeader("Content-Encoding", "gzip");
response.getOutputStream().write(b);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
class GzipHttpServletResponse extends HttpServletResponseWrapper{
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private PrintWriter pw;
public GzipHttpServletResponse(HttpServletResponse response) {
super(response);
}
//servlet是使用getOutputStream获取流输出的
//覆盖这个方法,把数据写到一个缓存中,就可以进行获得数据
public ServletOutputStream getOutputStream() throws IOException {
ServletOutputStream sos = super.getOutputStream();
MyServletOutputStream msos = new MyServletOutputStream(sos,baos);
return msos;
}
//1如果是字符流则转成字符流,2把数据弄到baos中去
//查看API文档,PrintWriter的构造函数可以直接调用字符流进行输出
public PrintWriter getWriter() throws IOException {
pw = new PrintWriter(new OutputStreamWriter(baos, super.getCharacterEncoding()));
return pw;
}
public byte[] getBufferData() {
try {
//关闭Printwriter流
if(pw!=null)
pw.close();
baos.flush();
} catch (IOException e) {
e.printStackTrace();
}
return baos.toByteArray();
}
}
class MyServletOutputStream extends ServletOutputStream{
private ServletOutputStream sos;
private ByteArrayOutputStream baos;
public MyServletOutputStream(ServletOutputStream sos,ByteArrayOutputStream baos){
this.sos = sos;
this.baos = baos;
}
public void write(int b) throws IOException {
baos.write(b);
}
}
案例四:对于常用的动态资源生成的结果进行缓存
web.xml配置 CacheResultFilter
只为category.jsp服务
建立CacheResultFilter 过滤器
建立cache HashMap。