首页 文章 精选 留言 我的

精选列表

搜索[后台管理模板],共10000篇文章
优秀的个人博客,低调大师

后台(34)——MyBatis概述

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl MyBatis简介 MyBatis原本是apache的一个开源项目iBatis, 2010年该项目由apache software foundation 迁移到了google code并改名为MyBatis 。2013年11月MyBatis又迁移到Github。 The MyBatis SQL mapper framework makes it easier to use a relational database with object-oriented applications. MyBatis couples objects with stored procedures or SQL statements using a XML descriptor or annotations. Simplicity is the biggest advantage of the MyBatis data mapper over object relational mapping tools. MyBatis是一个优秀的持久层框架,它对JDBC操作数据库的过程进行了封装,使开发者只需要关注SQL本身,而不需要开发人员花费大量的精力去处理例如注册驱动、创建connection、创建statement、手动设置参数等JDBC操作。 Mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由MyBatis框架执行sql并将结果映射成java对象并返回。 更多介绍,敬请参见MyBatis官方网站 MyBatis框架 1、SqlMapConfig.xml是MyBatis的全局配置文件,它配置了MyBatis的运行环境等信息。 2、mapper.xml是sql映射文件,它配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载 3、通过MyBatis配置信息构造SqlSessionFactory(会话工厂) 4、由会话SqlSessionFactory(工厂)创建SqlSession(会话)操作数据库 5、MyBatis底层自定义Executor(执行器)接口用于执行数据库操作,该接口有两个实现:基本执行器和缓存执行器。 6、MappedStatement是MyBatis的底层封装对象,它封装了操作数据库的sql语句,输入参数,输出结果等信息。mapper.xml文件中每一个sql语句对应一个MappedStatement对象,sql语句的id即是MappedStatement的id。 7、MappedStatement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql前将输入的java对象映射至sql中 8、MappedStatement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过MappedStatement在执行sql后将输出结果映射至java对象中 MyBatis开发环境 在利用MyBatis开发前,请移步MyBatis官网下载开发所有的jar包、开发指南,说明文档等资料。

优秀的个人博客,低调大师

后台(32)——内省Introspector

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 内省(Introspector)简介 内省Introspector是一种特殊的反射技术,常用于操作JavaBean。 字段和属性以及JavaBean 先来看我们经常写的一种类: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; public class Girl { private String name; private int age; private int bust; private int waist; private int hip; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getBust() { return bust; } public void setBust(int bust) { this.bust = bust; } public int getWaist() { return waist; } public void setWaist(int waist) { this.waist = waist; } public int getHip() { return hip; } public void setHip(int hip) { this.hip = hip; } } 在该类中,我们定义了几个字段并且为它们生成了对应的getXXX()和setXXX()。在很多时候我们喜欢把name,age,waist这些东西叫属性。其实,更加规范的的说法应该是:把有getXXX()或者setXXX()的变量叫做属性,把没有getXXX()或者setXXX()的变量称作字段。 很多时候,我们会看到这样的类:里面只有属性及其对应的get和set方法,这样的类也被称为JavaBean,比如此处的Girl类。 内省Introspector的使用方式 在此介绍与内省Introspector相关的操作 /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ private static void testPropertyDescriptor1() throws IntrospectionException{ BeanInfo beanInfo = Introspector.getBeanInfo(Girl.class); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { System.out.println(propertyDescriptor.getName()); } } 在此,我们利用属性描述器PropertyDescriptor获取Bean的属性,结果如下: age bust class hip name waist 嗯哼,发现了么?我们不但获取到了Gril类的五个属性还获取到了它的父类Object的属性class。 继续来看下面的例子: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ private static void testPropertyDescriptor2() throws Exception{ Girl girl = new Girl(); PropertyDescriptor propertyDescriptor = new PropertyDescriptor("age", Girl.class); Method setter = propertyDescriptor.getWriteMethod(); setter.invoke(girl, 18); Method getter = propertyDescriptor.getReadMethod(); Object age = getter.invoke(girl, null); System.out.println("age="+age); } 输出结果: age=18 代码解析如下: 得到与属性对应的属性描述器PropertyDescriptor,请参见代码第7行 得到该属性的set方法后为对象赋值,请参见代码第8—9行 得到该属性的get方法后取出属性值,请参见代码第10—11行 Beanutils BeanUtils是Apache提供的操作JavaBean的工具,它使用简单,操作方便。如有需要,可至其官方网站详细了解;在此不再赘述。

优秀的个人博客,低调大师

后台(33)——注解Annotation

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 注解Annotation 关于注解,请参见《 详解Android主流框架不可或缺的基石》,在此不再赘述

优秀的个人博客,低调大师

后台(31)——反射Reflection

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 关于该部分内容,敬请参见《详解Android主流框架不可或缺的基石》,不再赘述

优秀的个人博客,低调大师

后台(29)——动态代理

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 本文已经deprecated,关于动态代理,请参见从狡猾的房产中介来看动态代理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 代理模式简介 代理模式(Proxy Pattern)是面向对象中一种非常常见的设计模式。其实,不单是在软件开发领域,在我们的日常生活中对于代理也时常可见。比如:房东要将自家的房租出售,于是到房地产中介公司找一个代理,由他来帮自己完成销售房屋,签订合同等等事宜。 在此,就以该生活场景为蓝本介绍Java的代理模式。 静态代理 房东通过一纸协议将自己的房子挂靠在房屋中介;嗯哼,我们来一起瞅瞅这个房东和中介公司共同达成的协议: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; public interface TradeProtocol { public void sellHouse(int money); } 嗯哼,这个协议很简单,房东委托中介公司售卖自己的房子。 既然是房东和房屋中介共同达成的协议,那么房东和中介都需要遵守该协议。 先来看房东: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; public class Owner implements TradeProtocol{ @Override public void sellHouse(int money) { System.out.println("我是房主,我的房子卖了"+money+"块钱"); } } 再来看中介: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; public class HouseAgent implements TradeProtocol { private TradeProtocol mHouseProtocol; public HouseAgent(TradeProtocol houseProtocol){ mHouseProtocol=houseProtocol; } @Override public void sellHouse(int money) { System.out.println("我是中介,业主的房子卖了"+money+"块钱"); mHouseProtocol.sellHouse(money); } } 请注意HouseAgent的实现 在HouseAgent的构造方法中传入TradeProtocol的对象比如Owner 在HouseAgent的sellHouse()中调用TradeProtocol的对象(比如Owner)的sellHouse() 所以,HouseAgent售卖(sellHouse())房子,实际上是房东售卖了房屋 测试如下: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; public class Test { public static void main(String[] args) { Owner owner=new Owner(); HouseAgent houseAgent=new HouseAgent(owner); houseAgent.sellHouse(10000*100); } } 测试结果: 我是中介,业主的房子卖了1000000块钱 我是房主, 我的房子卖了 1000000块钱 在该静态代理中,房东将房屋的售卖交给了中介代理,中介将房屋出售后又把钱一分不少地交给了房东。咦,这咋不对呢?现实中有这样大公无私,视金钱如粪土的房屋中介么?没有!绝对没有! 那么,中介是怎么赚钱的呢?我们继续往下看 动态代理 与之前一样,房东和中介之间存有一纸协议: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; public interface TradeProtocol { public void sellHouse(int money); } 房东遵守该协议: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; public class Owner implements TradeProtocol{ @Override public void sellHouse(int money) { System.out.println("我是房主,中介告诉我:房子卖了"+money+"块钱"); } } 现在,房东又去房屋中介公司挂靠自己的房子,到了那一看:原来熟悉的那个代理出去办事了,刚好不在。正准备走呢,中介公司的经理挺着啤酒肚走过来,笑嘻嘻地说:请问您是来办理业务的吗?来,请坐,我给你们引荐以为我们这里服务最好的一个房屋代理人员办理您的相关事宜 嗯哼,我们来看看这个代理是怎么卖掉房东的房子的: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { TradeProtocol owner=new Owner(); ClassLoader classLoader=owner.getClass().getClassLoader(); Class<?>[] interfaces = owner.getClass().getInterfaces(); TradeProtocol houseAgent=(TradeProtocol) Proxy.newProxyInstance(classLoader,interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { Object object=null; System.out.println("我是中介,业主的房子我实际卖了"+args[0]+"块钱"); object=method.invoke(owner, new Object[]{(Integer)args[0]/2}); System.out.println("我是中介,这次交易我赚了不少钱呢"); return object; } }); houseAgent.sellHouse(10000*100); } } 在该实现中由系统自动地为我们创建了一个代理Proxy.newProxyInstance() 结果如下: 我是中介,业主的房子我实际卖了1000000块钱 我是房主,中介告诉我:房子卖了500000块钱 我是中介,这次交易我赚了不少钱呢 哇哈,中介把房子卖了100W却告诉房东只买了50W,自己狠狠地赚了一笔! 嗯哼,这个例子我们看完了,在此对照Test类分析动态代理的实现 动态代理与静态模式的原理是一样的,只是它没有具体的代理类而是通过Proxy在JVM运行时利用反射动态地生成了一个代理。 请注意Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法的三个参数 ClassLoader:类加载器,传入和被代理类使用的相同的类加载器即可 Class<?>[] interface:代理类要实现的接口,传入和被代理类使用的相同的接口即可 InvocationHandler h:当通过代理对象调用一个方法的时候,该方法的调用会被转发至InvocationHandler接口的invoke()方法来执行具体的调用 请注意invoke(Object proxy, Method method, Object[] args)方法的三个参数 Object proxy:代理对象的引用 Method method:当前调用的方法 Object[] args:当前调用的方法的输入参数 由此可见:动态代理可方便地对委托类的方法进行某些处理,比如在方法实际调用前做一些过滤或者拦截操作,在方法调用后做一些善后处理等 后会有期 我们会在学习Spring框架时对Java动态代理机制做进一步的认识和理解

优秀的个人博客,低调大师

后台(27)——文件上传

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 文件上传概述 文件上传通常指的是用户在浏览器中通过表单form将文件上传至服务端 但是请注意该表单必须满足如下三个条件: form的method必须是post form的enctype必须是multipart/form-data form中利用input type=”file”提供上传的入口 Commons-fileupload简介 Commons-fileupload是Apache提供的一个用来处理表单文件上传的一个开源组件。该组件操作简单、API通俗易懂、性能优异。 使用Commons-fileupload需要导入两个jar包: commons-fileupload commons-io Commons-fileupload使用示例 我们先来准备一个表单form <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>文件上传</title> </head> <body> <form enctype="multipart/form-data" action="${pageContext.request.contextPath }/servlet" method="post" > 文件描述:<input type="text" name="description"/><br/><br/> 选择文件:<input type="file" name="photo"/><br/><br/> <input type="submit" value="上传"/><br/><br/> </form> </body> </html> 运行后效果如下图所示: 再来写一个处理文件上传的Servlet /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.UUID; 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; import org.apache.commons.io.FilenameUtils; public class UploadServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 判断表单是否支持文件上传 boolean isMultipartContent = ServletFileUpload.isMultipartContent(request); if (isMultipartContent) { DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload servletFileUpload = new ServletFileUpload(factory); servletFileUpload.setHeaderEncoding("UTF-8"); try { //得到并处理表单中的每个项 List<FileItem> fileItems = servletFileUpload.parseRequest(request); for (FileItem fileitem : fileItems) { if (fileitem.isFormField()) { processFormField(fileitem); } else { processUploadField(fileitem); } } } catch (Exception e) { e.printStackTrace(); } } } // 处理普通表单项 private void processFormField(FileItem fileitem) { try { String fieldName = fileitem.getFieldName(); String fieldValue = fileitem.getString("UTF-8"); System.out.println(fieldName + "=" + fieldValue); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } //处理上传表单项 private void processUploadField(FileItem fileItem) { try { //创建存放上传文件的目录 String folderName="upload"; String folderPath = getServletContext().getRealPath("/WEB-INF/"+folderName); File folder = new File(folderPath); if (!folder.exists()) { folder.mkdirs(); } //生成不重复的文件名 String fileName = fileItem.getName(); if (fileName != null) { fileName = FilenameUtils.getName(fileName); } fileName = UUID.randomUUID() + "_" + fileName; //按照日期生成子文件名称 String dateDirectory = makeDateDirectory(folder); //存放被上传的文件 File file=new File(folder, dateDirectory + File.separator + fileName); fileItem.write(file); } catch (Exception e) { e.printStackTrace(); } } //依据日期生成子文件夹 private String makeDateDirectory(File folder) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date date=new Date(); String dateDirectory = simpleDateFormat.format(date); File file = new File(folder, dateDirectory); if (!file.exists()) { file.mkdirs(); } return dateDirectory; } } 嗯哼,鉴于该示例比较简单和代码里已有的注释,在此不再对代码作详解。 文件上传的注意事项 实际开发中,在处理文件上传时请注意以下问题: 将保存上传文件的目录放在用户直接访问不到的地方,比如WEB-INF 上传文件重名的处理,可用UUID+文件名的方式 将上传文件合理地存入子目录中,比如按照日期 限制上传文件的大小,比如3M

优秀的个人博客,低调大师

后台(26)——Filter(3)

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 在这篇博客中我们利用Filter一并解决POST和GET请求的中文乱码。 测试表单 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Welcome</title> </head> <body> <form action="${pageContext.request.contextPath}/loginServlet" method="post"> <br/> 用 户:<input type="text" name="username"/><br/><br/> 密 码:<input type="password" name="password"/><br/><br/> <input type="submit" value=" 登 录 " /><br/> </form> </body> </html> 该页面非常简单,在点击”登录”之后跳转到loginServlet 测试Servlet /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGetAndPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGetAndPost(req, resp); } private void doGetAndPost(HttpServletRequest req, HttpServletResponse resp){ String username=req.getParameter("username"); System.out.println("---> username="+username); } } 在该页面中利用getParameter( )测试是否乱码 利用Filter过滤乱码 嗯哼,终于轮到今天的主角上场了 /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Map; import java.util.Map.Entry; import java.util.Set; 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; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; public class TestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) req; HttpServletResponse response=(HttpServletResponse) res; request=new MyHttpServletRequest(request); chain.doFilter(request, response); } @Override public void destroy() { } } class MyHttpServletRequest extends HttpServletRequestWrapper{ HttpServletRequest request; boolean isFirst=true; public MyHttpServletRequest(HttpServletRequest request) { super(request); this.request=request; } @Override public String getParameter(String name) { Map<String, String[]> parameterMap=getParameterMap(); String[] values=parameterMap.get(name); String value=values[0]; return value; } @Override public String[] getParameterValues(String name) { Map<String, String[]> parameterMap=getParameterMap(); String[] values=parameterMap.get(name); return values; } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> parameterMap = request.getParameterMap(); if(isFirst){ Set<Entry<String, String[]>> entrySet = parameterMap.entrySet(); for(Entry<String, String[]> entry:entrySet){ String[] values = entry.getValue(); for(int i=0;i<values.length;i++){ String value=values[i]; try { value=new String(value.getBytes("iso8859-1"),"UTF-8"); values[i]=value; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } isFirst=false; } return parameterMap; } } 在该类中通过继承HttpServletRequestWrapper实现自己的HttpServletRequest,即文中的MyHttpServletRequest。 覆写getParameter( )使其最终调用getParameterMap( ) 覆写getParameterValues( )使其最终调用getParameterMap( ) 在getParameterMap( )中将每个请求参数用UTF-8重新编码 配置文件 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>TestFilter</filter-name> <filter-class>cn.com.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>cn.com.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/loginServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> 嗯哼,至此利用Filter同时解决了Post和Get请求时带来的中文乱码问题。

优秀的个人博客,低调大师

后台(25)——Filter(2)

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 自动登录 在本篇博客中我们将完成一个小例子:利用Servlet、Filter、C3P0、MD5、HttpSession、Cookie实现等技术实现自动登录。 请看,本次示例的项目结构 在此,详解项目中的核心代码。 /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.com.bean.User; import cn.com.service.UserService; import cn.com.service.impl.UserServiceImpl; import cn.com.util.MD5Utils; public class LoginServlet extends HttpServlet { private final String MESSAGE="message"; @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username=request.getParameter("username"); String password=request.getParameter("password"); password=MD5Utils.md5(password); UserService userService=new UserServiceImpl(); User user=userService.findUser(username, password); if(user!=null){ String autologin=request.getParameter("autologin"); Cookie cookie=new Cookie("userinfo", user.getUsername()+"&"+user.getPassword()); cookie.setPath("/"); if(autologin==null){ cookie.setMaxAge(0); }else{ cookie.setMaxAge(60*60*24*3); } response.addCookie(cookie); request.getSession().setAttribute("user", user); request.getRequestDispatcher("/home.jsp").forward(request, response); }else{ request.setAttribute(MESSAGE, "用户名或者密码错误,请重新登录"); request.getRequestDispatcher("/login.jsp").forward(request, response); } } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } 获取表单传递过来的参数,请参见代码第24-25行 从数据库查询用户,请参见代码第28行 生成Cookie并返回给客户端,请参见代码第30-38行 依据是否自动登录设置Cookie的MaxAge,请参见代码第33-37行 将用户User保存到Session中,请参见代码第39行 /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com.filter; 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.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.com.bean.User; import cn.com.service.UserService; import cn.com.service.impl.UserServiceImpl; public class LoginFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) req; HttpServletResponse response=(HttpServletResponse) res; String path = request.getContextPath(); String uri = request.getRequestURI(); path = uri.substring(path.length()); if (!("/login.jsp".equals(path) || "/loginServlet".equals(path))) { User user=(User) request.getSession().getAttribute("user"); if(user==null){ String username=null; String password=null; Cookie[] cookies = request.getCookies(); for(int i=0;cookies!=null&&i<cookies.length;i++){ Cookie cookie=cookies[i]; String name=cookie.getName(); if("userinfo".equals(name)){ String value = cookie.getValue(); String[] strings = value.split("&"); username=strings[0]; password=strings[1]; break; } } UserService userService=new UserServiceImpl(); User u = userService.findUser(username, password); if(u!=null){ request.getSession().setAttribute("user", u); } } } chain.doFilter(request, response); } @Override public void destroy() { } } 如果访问的不是登录相关的资源那么就考虑是否自动登录,请参见代码第39-62行 如果用户没有登录过则开始自动登录,请参见代码第40-61行 自动登录成功后将User保存到Session中,请参见代码第59行 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>loginFilter</filter-name> <filter-class>cn.com.filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>loginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>cn.com.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/loginServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> 在web.xml中配置Servlet和Filter

优秀的个人博客,低调大师

后台(24)——Filter(1)

探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl Filter简介 JavaWeb中的过滤器Filter可以拦截所有访问Web资源(Servlet、JSP、HTML等等)的请求及其响应。Filter本身并不会产生请求和响应对象,它只提供过滤作用;比如:在Servlet被调用之前检查或者修改Request、Request Header、Request中的内容;在Servlet被调用之后检查或者修改Response、Response Header和Response中的内容。通过Filter我们可以实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息、验证、加密等一些非常实用的功能。 Filter入门示例 Filter的实现步骤如下: 1、创建一个类实现Filter接口 2、实现接口中方法,在doFilter( )中实现过滤 3、在web.xml文件中配置Filter 请看如下示例 先写一个Filter /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; 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; public class FilterTest implements Filter{ public FilterTest(){ System.out.println("调用Filter构造方法"); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("调用Filter的init()方法"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("doFilter()开始过滤"); chain.doFilter(request, response); System.out.println("doFilter()过滤结束"); } @Override public void destroy() { System.out.println("调用Filter的destroy()方法"); } } 再写一个Servlet /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HttpServletTest extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("调用HttpServlet的doGet()方法"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("调用HttpServlet的doPost()方法"); } } 最后在web.xml中配置Filter和Servlet <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>TestFilter</filter-name> <filter-class>cn.com.FilterTest</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>cn.com.HttpServletTest</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/servlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> 在这里也可看出:Filter的配置方式和Servlet非常类似!不仅如此,Filter的生命周期也与Servlet基本一致: 服务器启动时创建Filter对象并调用init(),该方法只调用一次. 访问的资源路径与Filter的拦截路径匹配时执行Filter中的doFilter()执行过滤(拦截) 当服务器关闭时调用Filter的destroy() 运行后输出结果: 调用Filter构造方法 调用Filter的init()方法 doFilter()开始过滤 调用HttpServlet的doGet()方法 doFilter()过滤结束 嗯哼,看到了吧:浏览器发起的请求会首先进入到Filter中后才进入到Servlet里;当Servlet中的方法执行完成后再次回到Filter。 在该实例中,我们只使用了一个Filter。其实,我们也可以编写多个Filter实现不同的功能,这些Filter将形成一个链条即FilterChain;当浏览器发起请求时,请求会先通过这个链条再到达资源。请注意一个小问题:链条中Filter的调用顺序是由其在web.xml中对应的<filter-mapping>的先后顺序决定的。 FilterConfig 我们知道Servlet中有一个ServletConfig;其实,在Filter也存在一个类似于ServletConfig的东西,它就是FilterConfig。嗯哼,想起来没有?——我们刚才的示例FilterTest中的init( )方法参数是不是一个FilterConfig呢? FilterConfig的作用: 1.获取Filter的名称 2.获取初始化参数 3.获取ServletContext对象 FilterConfig的常用方法: getFilterName( ) getInitParameter(String name) getInitParameterNames( ) getServletContext() Filter配置详解 Filter基本配置介绍 <filter> <filter-name>filter名称</filter-name> <filter-class>filter类全名</filter-class> </filter> <filter-mapping> <filter-name>filter名称</filter-name> <url-pattern>映射路径</url-pattern> </filter-mapping> 关于<url-pattern>的配置 1、完全匹配 必须以”/”开始. 2、目录匹配 必须以”/”开始,以*结束. 3、扩展名匹配 以*.xxx结束. 关于<servlet-name>的配置 可在<filter-mapping>中利用<servlet-name>对servlet进行过滤配置。即用<servlet-name>设置当前Filter拦截哪一个servlet 关于<dispatcher>的配置 可在<filter-mapping>中利用<dispatcher>指明:Filter在资源以什么方式被Servlet容器调用时才进行拦截。<dispatcher>的取值有:REQUEST、FORWARD、ERROR、INCLUDE 可在<filter-mapping>中利用<dispatcher>设置Web资源以什么方式被Servlet容器调用时Filter才进行拦截。<dispatcher>的取值有:REQUEST、FORWARD、ERROR、INCLUDE 1、REQUEST 目标资源被访问或者系统重定向后指向该目标资源时Filter才拦截。这也是默认的值 2、FORWARD 目标资源通过RequestDispatcher.forward(request, response)被调用时Filter才拦截 3、ERROR 目标资源是在系统处理异常时被调用 4、INCLUDE 目标资源通过RequestDispatcher.include(request, response)被调用时Filter才拦截

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册