首页 文章 精选 留言 我的

精选列表

搜索[后台控制台],共10006篇文章
优秀的个人博客,低调大师

后台(22)——AJAX

探索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 AJAX简介 AJAX(Asynchronous JavaScript And XML)不是一种新的编程语言,它指的是异步JavaScript。利用AJAX可在不重新加载整个页面的情况下与服务器通信并更新部分网页。 XMLHttpRequest AJAX 的核心是XMLHttpRequest,它是一种支持异步请求的技术。也就是说:在JavaScript中利用XMLHttpRequest可向服务器提出请求并处理响应且不阻塞用户当前操作。 XMLHttpRequest的创建 目前,市面上的大部分浏览器都支持XMLHttpRequest ,但是有的较老的浏览器比如:IE5和IE6却不支持。 所以,可以这么做: var xmlhttp; if (window.XMLHttpRequest) {//code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {//code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } XMLHttpRequest的常用方法 open(method,url,async) 建立与服务器的连接 method:指定请求方式,比如GET、POST;常用GET方式 url:请求的地址 async:是否使用异步方式请求,默认为true send(string) 将请求发送到服务器 如果是GET请求那么参数string为null,如果是POST请求那么利用string携带请求参数 setRequestHeader(header,value) 设置请求消息头;很少用到 XMLHttpRequest的常用属性 readyState readyState用于标识XMLHttpRequest的状态信息 readyState=0表示XMLHttpRequest对象未完成初始化,即刚创建。 readyState=1表示XMLHttpRequest对象开始发送请求;即调用了open方法,但还没有调用send方法,请求还没有发出 readyState=2表示XMLHttpRequest对象的请求发送完成;即send方法已经调用,数据已经提交到服务器,但没有收到任何响应 readyState=3表示XMLHttpRequest对象开始读取响应,还没有结束;即收到了响应消息头,但响应正文还没有收到 readyState=4表示XMLHttpRequest对象读取响应结束,响应消息头和响应正文都已收到 responseText 获得响应的文本内容 responseXML 获得响应的XML文档对象 status status用于标识Http请求的响应状态码 200 服务器响应正常 400 无法找到请求的资源 403 没有访问权限 404 访问的资源不存在 500 服务器内部错误 XMLHttpRequest的回调函数 每当readyState属性值改变时onreadystatechange函数就会被执行。所以我们可以在该函数中执行一些监听,比如:readyState=4而且status=200时处理服务器返回的数据 XMLHttpRequest使用示例 首先,我们写一个简单的jsp <%@ 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"> <script type="text/javascript" src="${pageContext.request.contextPath}/js/xmlhttprequest.js"></script> <title>测试AJAX</title> </head> <script type="text/javascript"> window.onload = function() { //第一步:获取XMLHttpRequest var req = getXMLHttpRequest(); //第四步:处理结果 req.onreadystatechange = function(){ if(req.readyState==4){ if(req.status==200){ alert(req.responseText); } } } //第二步:建立连接 req.open("get","${pageContext.request.contextPath }/servlet"); //第三步:发送请求 req.send(null); } </script> <body> </body> </html> 其中xmlhttprequest.js如下: function getXMLHttpRequest(){ var xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } return xmlhttp; } 然后,我们再写一个非常简单的Servlet /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestAJAXServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); writer.print("Hello AJAX"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } 运行后效果如下图所示:

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

后台(13)——Cookie

探索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 在之前学习HTTP时我们说:标准HTTP协议既有优点也有缺点,优点在于极大地减轻了服务器的压力,每一次请求不会造成不必要连接占用;缺点在于繁复地建立连接和断开连接,请求会传输大量重复的信息,所以随后出现了Keep-Alive、Cookie、HttpSession在某些程度上弥补了标准HTTP的缺点。从今天起,我们就开始学习Cookie和HttpSession 会话 在正式进入Cookie和HttpSession的学习之前,我们先来了解一个术语:会话。 简单地说:用户打开一个浏览器后点击网页中的多个超链接访问多个web资源,访问完毕后关闭浏览器。这个过程就称之为一个会话。在会话过程中会产生一些和用户操作密切相关的数据,所以客户端或者服务端需要为每个用户保存这些数据。例如:用户点击超链接通过一个Servlet购买了几件商品,客户端或者服务端应保存这些商品信息以便于用户点结帐Servlet时,结帐Servlet得到这些已购买的商品信息从而正确地结算。 那么客户端和服务端应该怎么样保存这些用户信息呢?通常地讲,有两种方式:Cookie和HttpSession Cookie Cookie属于客户端技术。服务端把每个用户的数据以cookie的形式返回到用户的浏览器的缓存中。当用户使用浏览器再去访问服务器里的web资源时,就会将这些Cookie携带给服务端 HttpSession Session属于服务器端技术。服务端为每个用户创建一个其独享的HttpSession对象,用户在访问服务器的web资源时可把不同用户的数据放在各自对应的session中 嗯哼,在了解了关于会话的基础知识之后,我们开始进入Cookie的学习 Cookie简介 Cookie是Servlet发送浏览器的少量信息,这些信息由浏览器保存,当浏览器访问Web资源时再将其发送回服务器。一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和值(VALUE)并且名称和值都是String类型的;除此以外,它还有一些其它信息:比如注释、路径和域限定符、最大生存时间maxAge和版本号。Cookie的值可以唯一地标识客户端,因此Cookie常用于会话管理。 Servlet可通过httpServletResponse.addCookie()将字段添加到HTTP 响应头以便将Cookie发送到浏览器。浏览器支持每台Web服务器20个Cookie,合计300个,并且将每个Cookie的大小限定为4KB. 浏览器通过向HTTP请求头添加字段将Cookie返回给Servlet。服务端可用HttpServletRequest.getCookies()从请求中获取Cookie. 一个服务端可以给同一个WEB浏览器发送多个Cookie,此时,如果有两个Cookie的name一样那么后者会覆盖前者。同一个WEB浏览器也可以存储多个不同服务端提供的Cookie。请注意,发送到浏览器的Cookie在默认情况下它是一个会话级别的cookie(即Cookie被存储在浏览器的内存中)当用户退出浏览器之后即被删除。若希望浏览器将该Cookie存储在磁盘上,则需要设置Cookie的maxAge. Cookie入门示例 请看如下示例: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; 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; public class CookieTest1 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); Cookie[] cookies = request.getCookies(); for(int i=0;cookies!=null&&i<cookies.length;i++){ Cookie cookie=cookies[i]; System.out.println(cookie.getName()+" "+cookie.getValue()); } if (cookies == null) { Cookie c1 = new Cookie("username", "tom"); Cookie c2 = new Cookie("password", "123456"); response.addCookie(c1); response.addCookie(c2); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } 代码解析如下: 生成两个Cookie,请参见代码第26-27行 利用response.addCookie()将Cookie返回给客户端,请参见代码第28-29行 利用request.getCookies()获取到浏览器携带至服务端的所有Cookie,请参见代码第20-24行 输出结果: username tom password 123456 我们再去浏览器中看看这些Cookie值,在此以谷歌浏览器为例 嗯哼,看到了吧,在此展示了Cookie的相关信息。 Cookie应用详解 cookie使用示例 在实际开发中Cookie有许多实用的地方,在此我们实现一个功能:利用Cookie记录上次访问时间 请看如下示例: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CookieTest2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String LAST_ACCESS_TIME="time"; response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); Cookie[] cookies = request.getCookies(); for(int i=0;cookies!=null&&i<cookies.length;i++){ Cookie cookie=cookies[i]; if(LAST_ACCESS_TIME.equals(cookie.getName())){ String time = cookie.getValue(); writer.println("<h4>"+"上次访问时间:"+time+"</h4>"); System.out.println("time="+time); } } Calendar calendar = Calendar.getInstance(); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); int date = calendar.get(Calendar.DATE); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND); String time = year+"/"+(month+1)+"/"+date+" " +hour+":"+minute+":"+second; Cookie cookie = new Cookie(LAST_ACCESS_TIME, time); response.addCookie(cookie); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } 代码解析如下: 得到所有Cookie,请参见代码第27行 从所有Cookie中筛选出上次访问的时间,请参见代码第28-35行 利用Cookie将最新的访问时间返回给浏览器 运行后效果如下图所示: 我们再去浏览器中看看这些Cookie值,在此以谷歌浏览器为例 cookie的maxAge 请注意,”过期时间:浏览会话结束时”,也就是说当我们结束了本次通话(关闭浏览器)之后这些Cookie就被删除了。这是为什么呢?之前我们也说过了:Cookie在默认情况下是一个会话级别的cookie,它存在于浏览器的内存中,当用户退出浏览器之后即被删除。现在,我们希望在关闭浏览器之后再次打开浏览器时依然可以显示上次登录的时间,这就需要设置Cookie的maxAge将该Cookie存储在磁盘上。打开API我们可以看到方法cookie.setMaxAge(int expiry),默认情况下expiry的值为-1,即关闭浏览器后Cookie被删除。如果设置expiry的值为0则表示立即删除Cookie;如果设置expiry的值为正数则表示将Cookie保存到硬盘中且在expiry秒后失效。 cookie的path 请注意,”路径:/TestCookie01”,这个路径是不是觉得有点眼熟呢?哇哈,它就是我们通过request.getContextPath();获取到的应用上下文路径!所以,默认情况下通过cookie.getPath()获取到Cookie的路径正是应用的上下文路径,当然你也可以cookie.setPath()为Cookie设置path。这个path有啥用呢?我们打开官方文档看看是怎么说这个path的:在为Cookie设置path(即目录)后,Cookie对于该指定目录中的所有页面及该目录子目录中的所有页面都是可见的。哇哈,看到这里可能还是有点懵;嗯哼,我再换个方式说:如果浏览器访问的资源路径(即URI而非URL)如果是以Cookie的path开头的那么浏览器就会将该Cookie携带至服务端;否则不会携带该Cookie。举个例子:比如Cookie的path是/TestCookie01/hello;浏览器访问的是xxxx/TestCookie01/hello/haha/test.html那么浏览器就会将该Cookie携带至服务端;假如浏览器访问的是xxxx/TestCookie01/abcde/ppha/test.html那么浏览器就不会将该Cookie携带至服务端

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

后台(14)——HttpSession

探索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 在之前学习HTTP时我们说:标准HTTP协议既有优点也有缺点,优点在于极大地减轻了服务器的压力,每一次请求不会造成不必要连接占用;缺点在于繁复地建立连接和断开连接,请求会传输大量重复的信息,所以随后出现了Keep-Alive、Cookie、HttpSession在某些程度上弥补了标准HTTP的缺点。在上一篇博客我们学习了Cookie,在本篇博客中我们来一起学习HttpSession HttpSession简介 与客户端技术Cookie技术不同,HttpSession是服务端技术。在WEB开发中,服务器可为用户的每个浏览器创建一个会话对象即HttpSession。默认情况下,一个浏览器独占一个HttpSession对象。因此,服务器程序可将用户数据存入用户浏览器对应的独占的HttpSession中,当用户使用浏览器访问当前应用下的其它程序时,其它程序也可以从该HttpSession中取出该用户的数据。 HttpSession的特点 HttpSession对象由服务器创建 开发人员可调用request.getSession()得到该对象 在同一个会话下多个Servlet可共享数据 比如用户访问一个含有多个Servlet的网站,那么这些Servlet可共享一个HttpSession。比如,登录后把User存放到HttpSession后其他Servlet都可以使用该对象,并且在结算Servlet时用此对象判断用户是否登录。还记得之前的ServletContext么?对于存放在ServletContext中的数据,其它用户也有权限访问,但是存放在HttpSession中的数据其他应用是无法访问的。 Cookie只能存字符串但是HttpSession可以存对象 服务器重启时会将HttpSession中的数据保存到服务器硬盘,并在重启完成后将这些数据恢复到内存中。但是请注意这些数据要实现序列化否则无法保存和还原。 HttpSession常用方法 setAttribute( ) 向HttpSession中保存数据 getAttribute( ) 从HttpSession中获取数据 removeAttribute( ) 从HttpSession中移除数据 getId( ) 返回HttpSession的唯一标识符 setMaxInactiveInterval( ) 设置session的存活时间(单位是秒),默认为30分钟 invalidate() 销毁HttpSession HttpSession使用示例 请看如下代码: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import java.io.PrintWriter; 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 javax.servlet.http.HttpSession; public class TestHttpSession extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String NAME="name"; String JSESSIONID="JSESSIONID"; response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); HttpSession httpSession = request.getSession(); String httpSessionID=httpSession.getId(); String name=(String) httpSession.getAttribute(NAME); Cookie[] cookies = request.getCookies(); for(int i=0;cookies!=null&&i<cookies.length;i++){ Cookie cookie=cookies[i]; if (JSESSIONID.equals(cookie.getName())) { writer.println("<h4>"+"JSESSIONID="+cookie.getValue()+"</h4>"); } } if(httpSessionID!=null){ writer.println("<h4>"+"httpSessionID="+httpSessionID+"</h4>"); } if(name==null){ writer.println("<h4>"+"还没有存放数据"+"</h4>"); httpSession.setAttribute(NAME, "zxx9527"); }else{ writer.println("<h4>"+"从HttpSession中获取到数据name="+name+"</h4>"); } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } 代码解析如下: 为当前应用创建HttpSession,请参见代码第25行 获取HttpSession的ID,请参见代码第26行 获取名字为JSESSIONID的Cookie的值,请参见代码第32行 将数据保存至HttpSession中,请参见代码第40行 从HttpSession中取出数据,请参见代码第27行 运行后如效果如下图所示: 浅析request.getSession( ) 在刚才的示例中我们只调用了一句request.getSession()就可以开始对HttpSession的操作,那么这句代码的内部到底做了哪些事情呢? 1、获取名称为JSESSIONID的Cookie的值 2、如果没有获取到该Cookie那么就创建一个新的HttpSession且为其分配一个唯一的SessionID并且立马为浏览器生成一个名字为JSESSIONID值为sessionID的Cookie 3、如果可以获取到该Cookie,则取出该cookie的值(即HttpSession对象的SessionID),再依据此SessionID从服务器中找到与其对应的HttpSession 应对浏览器禁用Cookie的情况 通过之前的讲解我们知道:HttpSession是依赖于Cookie的,如果用户禁用了Cookie此时也就谈不上什么HttpSession了。所以,我们需要方法应对该情况的发生。 解决方案:利用response.encodeURL( )方法对网站的所有URL进行重写 执行request.getSession( ) 对sendRedirect( )涉及到的url地址进行重写 对表单的action和超链接的url进行重写 在重写URL后新的URL中就会包含JSESSIONID的值,比如JSESSIONID=30578BE1BD6600C2908607EE381BBB9B,从而将JSESSIONID携带至服务端。

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

后台(08)——Tomcat

探索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 本文简介 开发中常用的WEB服务器有:WebLogic、WebSphereAS、Tomcat、JbossAS等等。在本阶段的学习中我使用的是Tomcat,故在此记录Tomcat的安装和项目部署过程。 Tomcat的安装与配置 第一步:下载Tomcat 在Tomcat官网下载Tomcat,我下载的是Tomcat7对应的apache-tomcat-7.0.52.zip压缩包。 第二步:解压Tomcat 解压apache-tomcat-7.0.52.zip 第三步:配置环境变量 在环境变量中配置以下变量: 在PATH中配置tomcat的路径,比如:D:\developKits\apache-tomcat-7.0.52\bin; 配置JAVA_HOME,比如:C:\Program Files\Java\jdk1.8.0_60 配置CATALINA_HOME,比如:D:\developKits\apache-tomcat-7.0.52 第四步:启动Tomcat 第一种方式: 在D:\developKits\apache-tomcat-7.0.52\bin中双击startup.bat 第二种方式: 在DOS下执行startup 启动成功后,如下图所示: 在浏览器中输入:http://localhost:8080/ ,如下图所示: Tomcat的端口占用问题 Tomcat默认的端口号是8080,但我们时常可发现:由于端口号被占用导致Tomcat启动失败,可以这么做来解决该问题: 在DOS中执行 netstat -ano | findstr “8080” 找到占用8080端口的进程的PID 在任务管理中的详细信息中找到该PID对应的应用并将其结束 除了该方式以外,还以修改Tomcat默认的端口号。请找到D:\developKits\apache-tomcat-7.0.52\conf\server.xml中的 <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> 将此处的端口号修改为8081再重启Tomcat即可。 Eclipse集成Tomcat 1、在Eclipse中添加Tomcat 在Window—>Preferences—>Server—>Runtime Environments—>add添加刚才已经配置好的Tomcat 2、为项目添加index.jsp 在项目的WebContent目录下添加index.jsp文件,请参照下图: 为什么要在此添加index.jsp呢?我们来瞅瞅Tomcat的web.xml文件中的配置,请参照下图: 嗯哼,看到了吧,Tomcat把index.jsp作为了项目的首页! 3、部署项目至Tomcat 项目右键—->Run As—>Run On Server—>Tomcat7;此时,发现没有运行成功。请在Eclipse的Server视图中remove掉刚才的项目,请参照下图: 在remove操作后,请继续在Eclipse的Server视图中点击Tomcat右键执行Clean。在完成以上两步操作后,仍在Eclipse的Server视图点击Tomcat右键Open,设置Server Locations,请参照下图: 最后,请保存刚才的配置。然后再次部署项目,即可成功! 此时,我们在本地找到Tomcat的webapps文件夹,请参照下图: 嗯哼,刚才部署的项目已经保存到该文件夹下面了。 由于软件版本差异,所以在Eclipse集成Tomcat的过程中或许有些地方不太一样,这个无关紧要,也不用太纠结;毕竟主要流程是一致的。 至此,关于Tomcat就介绍完了,谢谢。

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

后台(06)——JDBC

探索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 本文简介 本文主要介绍JDBC的基础知识及其用法。 JDBC简介 JDBC(java database connectivity)是SUN公司提供的一套利用Java语言操作数据库的标准规范。 在JDBC中定义了许多接口而数据库厂商在其数据库驱动中实现了这些接口。关于JDBC与数据库驱动的关系,请参见下图: JDBC中定义的接口(规范),各数据库厂商(比如MySQL,Oracle,DB2等)在其数据库驱动中实现了这些接口(规范)。所以,JDBC屏蔽了Java与不同数据库打交道的细节问题;假如项目原本使用的是MySQL,在某段时间后换成了Oracle,那我们基本不用去修改原来项目中的SQL语句,只需要把JDBC中MySQL的数据库驱动切换成Oracle对应的数据库驱动即可。 JDBC的核心技术点: DriverManager:用于加载驱动 Connection: 用于创建与数据库的连接 Statement: 用于操作sql语句 ResultSet: 结果集或一张虚拟表 JDBC的操作步骤: 加载驱动 创建连接 创建Statement对象 执行sql语句且返回结果 处理结果 关闭资源 嗯哼,在了解这些之后我们来看一个简单的示例,代码如下: package cn.com; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; /** * 原创作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ public class UnitTest { @Test public void testJDBC1() { Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root"); statement = connection.createStatement(); String sql = "select * from student"; resultSet = statement.executeQuery(sql); while (resultSet.next()) { Student student = new Student(); int id = resultSet.getInt("studentid"); String name = resultSet.getString("studentname"); student.setStudentID(id); student.setStudentName(name); System.out.println(student); } } catch (Exception e) { e.printStackTrace(); } finally { if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } resultSet = null; } if (statement != null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } statement = null; } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } connection = null; } } } } 在该示例中,利用JDBC从数据库查询数据。代码解析如下: 第一步: 加载MySQL数据库驱动,请参见代码第22行 第二步: 创建与数据的连接,请参见代码第23行 第三步: 创建用于执行SQL语句的Statement对象,请参见代码第24行 第四步: 利用Statement执行SQL语句且得到结果集,请参见代码第26行 第五步: 处理结果集,请参见代码第27-34行 第六步: 关闭资源,请参见代码第37-64行 详解JDBC常用类和接口 通过刚才的例子,我们对于JDBC的使用有了初步的了解和认知,现在此基础上详解JDBC常用的类和接口 java.sql.Drivermanager类 java.sql.Drivermanager类用于加载(注册)驱动和与数据库建立连接。 利用java.sql.Drivermanager类用于加载(注册)驱动 在此,我们采用的是: Class.forName(“com.mysql.jdbc.Driver”); 还有另外一种方式: DriverManager.registerDriver(new com.mysql.jdbc.Driver()); 该方式不但强烈依赖数据库的驱动jar而且会导致驱动被重复注册2次。故不建议使用该方式 利用java.sql.Drivermanager类与数据库建立连接 比如,该示例中: DriverManager.getConnection(“jdbc:mysql://localhost:3306/db1”,”root”, “root”); 其中jdbc表示协议,mysql表示子协议,localhost代表IP,3306表示端口号,db1表示要连接的数据库,第一个root表示用户名,第二个root表示密码。这些值是我示例中的配置,在项目中使用时请替换这些值。 java.sql.Connection接口 java.sql.Connection是一个接口,它用于与数据库交互;各数据库驱动中均实现了该接口。java.sql.Connection最常用的操作是创建用于执行SQL语句的Statement,即: connection.createStatement(); java.sql.Statement接口 java.sql.Statement接口用于操作SQL语句并返回相应的结果集;各数据库驱动中均实现了该接口。java.sql.Statement的常用方法如下: executeQuery(String sql) 该方法用于执行select语句并根据查询语句返回结果集 executeUpdate(String sql) 该方法用于执行insert、update、delete语句并返回受影响的行数 execute(String sql) 此方法可以执行任意SQL语句。当且仅当执行select语句且有返回结果时该方法返回true, 其他情况下该方法返回false java.sql.ResultSet接口 java.sql.ResultSet用于保存执行SQL语句之后得到的结果集;各数据库驱动中均实现了该接口。 ResultSet对外暴露一个游标,该游标默认指向结果集第一行之前。ResultSet常见方法释义如下: boolean next() 将游标从当前位置向下移动一行 boolean previous() 将光标移动到此ResultSet对象的上一行。 void afterLast() 将光标移动到末尾,正好位于最后一行之后。 void beforeFirst() 将光标移动到开头,正好位于第一行之前。 Object getObject(int columnIndex); 根据序号取值,索引从1开始 Object getObject(String ColomnName); 根据列名取值 int getInt(int colIndex) 以int形式获取ResultSet结果集当前行指定列号值 int getInt(String colLabel) 以int形式获取ResultSet结果集当前行指定列名值 float getFloat(int colIndex) 以float形式获取ResultSet结果集当前行指定列号值 float getFloat(String colLabel) 以float形式获取ResultSet结果集当前行指定列名值 String getString(int colIndex) 以String形式获取ResultSet结果集当前行指定列号值 String getString(String colLabel) 以String形式获取ResultSet结果集当前行指定列名值 Date getDate(int columnIndex); 以Date形式获取ResultSet结果集当前行指定列号值 Date getDate(String columnName); 以Date形式获取ResultSet结果集当前行指定列号值 void close() 关闭ResultSet对象 在从ResultSet中获取到数据库中数据后,我们就将这些数据封装到JavaBean中;在此请注意Java的数据类型与数据库的数据类型的对应关系: 利用preparedStatement防止SQL注入 preparedStatement(预编译对象)是Statement的子类,它具有如下特点: 预先编译SQL语句 性能优异 在SQL语句中使用占位符 在此利用preparedStatement优化刚才的示例,代码如下: package cn.com; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.Test; /** * 原创作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ public class UnitTest { @Test public void testJDBC2() { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root"); String sql = "select * from student where studentid=? and studentname=?"; preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1, 4); preparedStatement.setString(2, "波少野结衣"); resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { Student student = new Student(); int id = resultSet.getInt("studentid"); String name = resultSet.getString("studentname"); student.setStudentID(id); student.setStudentName(name); System.out.println(student); } } catch (Exception e) { e.printStackTrace(); } finally { if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } resultSet = null; } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } preparedStatement = null; } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } connection = null; } } } } 至此,关于JDBC的基础知识就介绍完了,谢谢。

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

微软 Edge 143 将移除网络控制台工具

微软 Edge 浏览器提供了名为“Network Console Tool”的开发者工具,该工具主要用于网络请求的捕获和分析,帮助开发者深入查看浏览器与服务器之间的通信,让开发者可以调试和优化网络请求。 根据微软工程师发布的 issue,他们计划从 Edge 143 版开始删除这个功能,原因是微软没有能力继续维护这个工具,接下来的主要任务是提供稳定功能并改进与 Chrome 的兼容性。 https://github.com/MicrosoftEdge/DevTools/issues/348 作为替代方案,微软建议开发者使用 Microsoft Visual Studio Code 的 REST 客户端扩展进行 API 开发和测试,微软 Edge 浏览器本身不再提供直接的替代方案。

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

ECS控制台标签操作的N种姿势

背景 弹性计算云服务器、磁盘、安全组、镜像、密钥对、网卡支持标签。 限制 随实例一起创建的资源,在创建的时候tag是会作用到实例及其创建的磁盘及网卡上的。 变更Tag时,只作用单资源,比如实例就实例,磁盘就磁盘,网卡就网卡。 操作 实例 标记资源标签、取消标记、修改标签 方式一:方式二:方式三: 通过标签过滤资源 方式一:。方式二: 磁盘 标记资源标签、取消标记、修改标签 方式一:方式二: 通过标签过滤资源 方式一: 镜像 标记资源标签、取消标记、修改标签 方式一:方式二: 通过标签过滤资源 方式一: 快照 标记资源标签、取消标记、修改标签 方式一:方式二: 通过标签过滤资源 方式一: 安全组 标记资源标签、取消标记、修改标签 方式一:点击修改方式二:方式三: 通过标签过滤资源 方式一: 网卡 标记资源标签、取消标记、修改标签 方式一: 点击修改 通过标签过滤资源 方式一: 密钥对 标记资源标签、取消标

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

后台(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

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

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

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册