首页 文章 精选 留言 我的

精选列表

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

后台(17)——JSP(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 今天我们继续学习JSP中的EL和JSTL。 EL表达式 EL(expression language)表达式是JSP中获取数据的一种规范,它主要用于简化jsp中java代码开发。 利用EL表达式获取数据 我们利用EL表达式获取数据,但是请务必注意它只可以获取存在4个作用域中的数据。 语法格式:${ } 比如,我们在session中存了数据: session.setAttribute(“name”, “波少野结衣”); 那么我们可以利用EL表达式获取存的数据 ${name} 嗯哼,这里使用EL表达式就非常简单了,究其根本是因为${}背后执行的是pageContext.findAttribute( )。 与此类似,如果我们有一个User类,其中有name属性,user是该类的对象。现在将该对象保存到域中后,如果要获取该对象的name可以这么写: ${user.name} 该方式就等效于user.getName()。也就是说在EL表达式中.运算符相当于调了getter方法。同理如果User中有一个Address属性,Address中又有一个city,我们也可以通过该方式获取city的值 ${user.address.city} 还有一个功能与.运算符非常类似的运算符[],但它比.运算符要强大许多,在此不再赘述。 EL表达式的简单运算 我们还可以利用EL表达式做一些简单的运算。 利用empty判断null 它会将空字符串和没有元素的集合都判断为null即返回true,示例如下: ${empty object} EL的三元运算符 请看如下示例: ${empty user ? “未登录”:”已经登录”} EL表达式的隐式对象 在之前的文章中介绍了JSP的内置对象,在此列举几个EL表达式的常用对象 pageContext 对应于JSP页面中的pageContext对象 pageScope 代表page域中用于保存属性的Map对象 requestScope 代表request域中用于保存属性的Map对象 sessionScope 代表session域中用于保存属性的Map对象 applicationScope 代表application域中用于保存属性的Map对象 param 表示一个保存所有请求参数的Map对象 paramValues 表示一个保存了所有请求参数的Map对象,它对于某个请求参数返回一个string类型数组 header 表示一个保存了所有http请求头字段的Map对象 headerValues 表示一个保存了所有http请求头字段的Map对象,返回string类型数组 cookie 表示一个保存了所有cookie的Map对象 initParam 表示一个保存了所有web应用初始化参数的map对象 JSTL JSTL简介 从JSP 1.1规范开始JSP就支持使用自定义标签,使用自定义标签极大地降低了JSP页面的复杂度,同时增强了代码的重用性,所以自定义标签在WEB应用中被广泛使用。故,许多WEB应用厂商都开发出了自己的一套标签库,这导致出现了许多功能相同的标签,令开发人员手忙脚乱,无所适从。为了解决该问题,Apache开发了一套用于解决这些常用问题的自定义标签库,这套标签库被SUN公司定义为标准标签库(The JavaServer Pages Standard Tag Library),简称JSTL。在开发中可使用JSTL实现JSP页面中逻辑处理,如判断、循环等等操作。 添加JSTL <%@ taglib uri=”http://java.sun.com/jsp/jstl/core” prefix=”c” %> 利用taglib指令设置JSTL的路径和前缀名 导入包jstl.jar和standard.jar JSTL常用标签 <c:set>标签 用于设置各种域中的属性 <c:out>标签 用于输出一段文本内容到客户端浏览器 <c:remove>标签 用于删除各种域中的属性 <c:if>标签 用于条件判断 <c:choose>标签 该标签非常类似于Java中的switch语句,用于多个条件选择。它必须与<c:when>和<c:otherwise>一起使用 <c:forEach>标签 用于对集合对象进行循环迭代操作 请看如下示例: <%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSTL</title> <style type="text/css"> </style> </head> <body> <!-- 测试set、remove、out --> <c:set var="number" value="9527" scope="session"/> number=<c:out value="${number}"/> <c:remove var="number" scope="session"/> number=<c:out value="${number}" default="没有取到number的值"/> </br> <!-- 测试if --> <c:if test="${9527>1234}"> zxx number is 9527 </c:if> </br> <!-- 测试choose --> <c:set var="size" value="${3}"></c:set> <c:choose> <c:when test="${size==1 }">The size is 1</c:when> <c:when test="${size==2 }">The size is 2</c:when> <c:when test="${size==3 }">The size is 3</c:when> <c:otherwise> The size is other </c:otherwise> </c:choose> </br> <!-- 测试forEach --> <c:forEach var="i" begin="1" end="20" step="3"> ${i}<br/> </c:forEach> </br> <% List list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); request.setAttribute("list", list); %> <c:forEach items="${list}" var="listitem"> ${listitem}<br/> </c:forEach> <br/> <!-- 测试forEach --> <% List arrayList = new ArrayList(); arrayList.add("aaa"); arrayList.add("bbb"); arrayList.add("ccc"); arrayList.add("ddd"); arrayList.add("eee"); request.setAttribute("arrayList", arrayList); %> <table border="1"> <tr> <th>数据</th> <th>索引</th> <th>计数</th> <th>是否是第一个</th> <th>是否是最后一个</th> </tr> <c:forEach items="${arrayList}" var="item" varStatus="vs"> <tr> <td>${item}</td> <td>${vs.index}</td> <td>${vs.count}</td> <td>${vs.first}</td> <td>${vs.last}</td> </tr> </c:forEach> </table> </body> </html> 运行后效果如下图所示:

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

后台(16)——JSP(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 JSP语法 在上一篇博客我们说过:JSP中可以书写Java代码也可以放置Html标签,但是从本质上来说JSP就是一个Servlet,所以我们站在Java的角度来看JSP的语法就会简单许多。 可以利用尖括号和百分号的形式在JSP文件中编写脚本 利用<% %>编写java代码,例如: <% Date date=new Date(); out.println(date.toLocaleString()); %> 在该脚本中的代码必须严格遵循Java语法且每行代码以分号结束,而且不能出现其它模板元素。因为JSP引擎在翻译JSP页面中会将该脚本中的Java代码将被原封不动地放到_jspService( )中 利用<%= %>实现输出,例如: <%= 9527+45 %> 等价于out.print(9527+45); 利用<%! %> 表示在类中定义全局成员和静态块 请注意在<%! %>定义的变量和方法和是全局的,它们会成为JSP对应的Servlet里的全局成员和方法。 利用<%– –%>添加JSP注释,例如: <%– 这是JSP注释 –%> 利用<!– –>添加Html注释,例如: <!– 这是网页注释 –> JSP指令 JSP指令是为JSP引擎而设计的,用于告知JSP引擎如何处理JSP页面中代码。 指令的语法格式: <%@ 指令名称 属性1=“属性值1” 属性2=“属性值2”…….%> 在JSP2.0规范中一共定义了三个指令:page、include、taglib。 现在来一起学习这三个指令,就从我们最熟悉的page开始。 page指令 page指令用于定义JSP页面的各种属性,比如在创建Web项目的时候系统会自动帮我们生成一个index.jsp,我们来瞅瞅该文件的第一行: <%@ page language=”java” import=”java.util.*” pageEncoding=”UTF-8”%> 以前看这行代码的时候有点懵懂,现在就清楚了:这就是一个page指令。在该指令中利用language属性指明该jsp文件中是java代码,利用import属性表明为该jsp文件导入了java.util包。说到导包有点人可能有疑惑了:我们没有导入java.lang为什么可以在JSP文件中写一些很基础的代码呢?这是因为系统会自动帮我们导入: import java.lang.*; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; 嗯哼,我们看看page指令常用的属性有哪些: session: 是否自动创建session对象,默认值是true errorPage: 假若页面中有错误跳转到指定的资源 isErrorPage: 是否创建throwable对象,默认是false contextType: 设置内容类型,等同于response.setContextType() pageEncoding: 告知JSP引擎用什么编码翻译该jsp文件 isELIgnored: 是否支持EL表达式,默认是false include指令 include指令用于把其它资源包含到当前页面中 静态包含: <%@ include file="xxxxxx.jsp" %> 动态包含: <jsp:include page="xxxxxx.jsp"></jsp:include> 请注意这两者的区别: 静态包含:在JSP转义时把两个文件合并 动态包含:在JSP转义时不会合并文件当代码执行到include时才包含另一个文件的内容 使用原则:尽量多采用静态包含 taglib指令 taglib指令用于在JSP页面中导入JSTL标签库。在导入JSTL标签库后就可用标签替换JSP中的java代码。 使用方式: <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> JSP的动作 在此介绍JSP常用的动作 <jsp:include> 用于动态地把其它资源包含到当前页面中 <jsp:forward> 用于请求转发 <jsp:param> 用于请求转发时携带参数 请看如下示例: <jsp:forward page="/test.jsp"> <jsp:param value="rose" name="name" /> <jsp:param value="23" name="age" /> </jsp:forward> 在此转发至test.jsp且携带了name和age两个参数 <jsp:useBean> 创建一个对象 <jsp:setProperty> 给对象的属性赋值 <jsp:getProperty> 取出对象的属性值 请看如下示例: <jsp:useBean id="p" class="cn.com.Person"/> <jsp:setProperty property="name" name="p" value="武疼兰"/> <jsp:getProperty property="name" name="p"/> 在此创建了cn.com.Person类的对象p,且为该对象的name属性赋值

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

后台(12)——Servlet(4)

探索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 在前几篇博客中我们学习了Tomcat,Http,Servlet,HttpServletResponse在此基础上我们来深入学习Servlet的请求即HttpServletRequest HttpServletRequest的简单使用 HttpServletRequest代表客户端的请求,当客户端通过HTTP协议访问服务器时与请求相关的所有信息都将被封装在这个对象中,所以我们可通过该对象获得客户端的相关信息。 常用的方法如下: getRequestURL():返回客户端发出请求时的完整URL getRequestURI():返回请求行中的资源名部分 getContextPath():返回请求的上下文路径 getQueryString():返回请求行中的参数部分 getParameter():返回参数中的具体值 getRemoteAddr():返回发出请求的客户端的IP地址 getRemoteHost():返回发出请求的客户端的完整主机名 getRemotePort():返回客户端所使用的网络端口号 getMethod():返回客户端使用的请求方式 getHeaderNames():返回此请求包含的所有头的名称 getHeader():返回指定的请求头的值 请看如下示例: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { getRequestInfo(request); getRequestHeader(request); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } //获取与请求相关的信息 private void getRequestInfo(HttpServletRequest request){ String method=request.getMethod(); StringBuffer requestURL = request.getRequestURL(); String requestURI = request.getRequestURI(); String contextPath = request.getContextPath(); String queryString = request.getQueryString(); String name=request.getParameter("name"); String remoteAddr = request.getRemoteAddr(); String remoteHost = request.getRemoteHost(); int remotePort = request.getRemotePort(); System.out.println("----> method="+method); System.out.println("----> requestURL="+requestURL); System.out.println("----> requestURI="+requestURI); System.out.println("----> contextPath="+contextPath); System.out.println("----> queryString="+queryString); System.out.println("----> remoteAddr="+remoteAddr); System.out.println("----> remoteHost="+remoteHost); System.out.println("----> remotePort="+remotePort); } //获取请求的Header中的信息 private void getRequestHeader(HttpServletRequest request){ Enumeration<String> headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()){ String headKey=headerNames.nextElement(); String headValue=request.getHeader(headKey); System.out.println(headKey+":"+headValue); } } } 代码写好了,我们现在通过浏览器发出请求: http://localhost:8081/TestServlet03/helloServlet?name=lucy 在Console中观察输入结果: —-> method=GET —-> requestURL=http://localhost:8081/TestServlet03/helloServlet —-> requestURI=/TestServlet03/helloServlet —-> contextPath=/TestServlet03 —-> queryString=name=lucy —-> name=lucy —-> remoteAddr=127.0.0.1 —-> remoteHost=127.0.0.1 —-> remotePort=63484 host:localhost:8081 connection:keep-alive cache-control:max-age=0 accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 upgrade-insecure-requests:1 user-agent:Mozilla/5.0 (Windows NT 10.0;Win64; x64)Chrome/47.0.2526.111 accept-encoding:gzip, deflate, sdch accept-language:zh-CN,zh;q=0.8 嗯哼,结合这些输出结果再回过头看这些方法就能有更好的体会。在此,再次强调一下:请注意getRequestURL()和getRequestURI()以及getContextPath()、getQueryString()这四个方法的区别 getRequestURL()返回的是请求的路径,但是不含请求的参数部分 getRequestURI()返回请求行中的资源名部分,但是不含有请求的主机和端口以及请求的参数部分 getContextPath()返回请求的上下文,即/+项目名称,比如此处的/TestServlet03 在前几篇博客中我们学习了Tomcat,Http,Servlet,HttpServletResponse在此基础上我们来深入学习Servlet的请求即HttpServletRequest HttpServletRequest处理表单请求 在刚才的示例中,我们利用getParameter()获取GET请求中请求参数中的具体值,那么在POST请求时又该怎么获取传递给服务端的值呢?请看如下示例 先准备一个表单: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Welcome</title> </head> <body> <form action="/TestServlet03/form" method="post"> 用 户:<input type="text" name="username"/> <br/><br/> 密 码:<input type="password" name="password"/> <br/><br/> 性 别:<input type="radio" name="gender" value="男" />男 <input type="radio" name="gender" value="女" checked="checked"/>女 <br/><br/> 爱 好:<input type="checkbox" name="hobby" value="摄影"/>摄影 <input type="checkbox" name="hobby" value="唱歌"/>唱歌 <input type="checkbox" name="hobby" value="拍照"/>拍照 <br/><br/> 城 市: <select name="city"> <option>------请选择------</option> <option value="dj">东京</option> <option value="db">大阪</option> <option value="xt">仙台</option> </select> <br/><br/> <input type="submit" value="欢迎注册VIP会员"/> </form> </body> </html> 再实现服务端的代码: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestForm extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { testForm1(request); } private void testForm1(HttpServletRequest request)throws ServletException,IOException { request.setCharacterEncoding("UTF-8"); Enumeration<String> parameterNames = request.getParameterNames(); while(parameterNames.hasMoreElements()){ String name = parameterNames.nextElement(); String[] values = request.getParameterValues(name); for(int i=0;values!=null&&i<values.length;i++){ System.out.println("name="+name+" "+"value="+values[i]); } } } } 代码解析如下: 利用setCharacterEncoding()设置编码方式 利用getParameterNames()获取所有请求参数的名称,请参见代码第28行 对于此处的表单POST提交而言传递的参数的名称分别为username,password,gender,hobby,city 获取每个参数对于的值,请参见代码第29-35行 嗯哼,现在我们通过浏览器来发起一个请求: 在Console观察打印信息: name=username value=杉原杏璃 name=password value=123456789 name=gender value=女 name=hobby value=摄影 name=hobby value=拍照 name=city value=dj 在实际开发中,我们可能需要将这些传递给服务端的信息封装成实体,请看如下示例: 先准备一个实体Entity: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.Serializable; import java.util.Arrays; public class User implements Serializable{ private String username; private String password; private String gender; private String[] hobby; private String city; 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 getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String[] getHobby() { return hobby; } public void setHobby(String[] hobby) { this.hobby = hobby; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Override public String toString() { return "User [username=" + username + ", password=" + password + ", gender=" + gender + ", hobby=" + Arrays.toString(hobby) + ", city=" + city + "]"; } } 请注意,该实体中字段的名字必须与表单中各个name的值相对应 再来看服务端的代码: private void testForm2(HttpServletRequest request)throws ServletException,IOException { try { request.setCharacterEncoding("UTF-8"); User user = new User(); Map<String,String[]> parameterMap = request.getParameterMap(); for (Map.Entry<String, String[]> map : parameterMap.entrySet()) { String name = map.getKey(); String[] values = map.getValue(); PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, User.class); Method method = propertyDescriptor.getWriteMethod(); if(values.length==1&&!name.equals("hobby")){ method.invoke(user, values[0]); }else{ method.invoke(user, (Object)values); } } System.out.println("------> "+user); } catch (Exception e) { e.printStackTrace(); } } 代码解析如下: 利用getParameterMap()得到请求中所有的参数及其对应的值,请参见代码第5行 注意:有的参数只有一个值,比如该示例中的username;有的参数会有多个值,比如该示例中的hobby 获取每个参数及其对应的值,请参见代码第7-8行 反射出每个参数在实体中的setter()方法,请参见代码第9-10行 设置每个参数对应的值,请参见代码第11-15行 请求重定向与请求转发的区别 我们知道: 利用response.sendRedirect()实现请求的重定向 利用request.getRequestDispatcher().forward()实现请求的转发 请注意它们的区别: 重定向时浏览器中的地址栏会发生变化,但是请求转发时浏览器中地址栏不会发生改变。从本质上来讲:重定向是两次不同的请求,而请求转发只向服务端的发送了一次请求由服务端的内部实现请求的跳转。 重定向可以跳转到应用的外部,而重定向的范围只能是应用的内部 请求转发可利用request.setAttribute()将数据传递到下一个Servlet且下一个Servlet可用request.getAttribute()取出数据;但是重定向不可以也没有道理这么做。至于为什么,请参考第一点。

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

后台(11)——Servlet(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 在前几篇博客中我们已经对Tomcat,Http,Servlet等方面有了简单的接触,在此基础上我们来深入学习Servlet的响应即HttpServletResponse. Request、Response简介 Web服务器接收到客户端的http请求后会针对每一次请求创建用于代表请求的request对象以及代表响应的response对象。故,若要获取客户机提交的数据,只需要处理request对象就行;若要向客户端输出数据,只需要处理response对象即可。 HttpServletResponse的简单使用 在此以HttpSerlet为例,介绍HttpServletResponse的使用方式,请看如下示例: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("GBK"); response.setContentType("text/html;chartset=GBK"); PrintWriter writer = response.getWriter(); writer.write("佐佐木希写真全集"); response.addHeader("Pragma", "no-cache"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Expires", "0"); response.setHeader("refresh", "10;url=http://blog.csdn.net/lfdfhl"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } 在这段代码中对Get请求做出响应,代码解析如下: 设置将发送到客户端的响应内容的字符编码,请参见代码第9行 在此将字符编码设置为GBK 设置将发送到客户端的响应内容的类型,请参见代码第10行 在此将内容的类型设置为text/html;chartset=GBK 设置客户端不缓存,请参见代码第13-15行 设置客户端在几秒钟后自动跳转,请参见代码第16行 亦可利用response.setContentType()设定发送到客户端的响应内容的类型,即: response.setContentType(“text/html;chartset=GBK”); 与此类似,也可设置重定向 response.setStatus(302); response.setHeader(“location”,”http://blog.csdn.net/lfdfhl“); 或者利用response.sendRedirect( )设置重定向 response.sendRedirect(“http://blog.csdn.net/lfdfhl“); 同理,我们可用ServletOutputStream向客户端返回字节流 response.setCharacterEncoding("GBK"); response.setContentType("text/html;chartset=GBK"); ServletOutputStream outputStream = response.getOutputStream(); outputStream.write("大泽玛利亚摄影写真".getBytes("GBK")); HttpServletResponse返回下载文件 刚才的示例中,我们只是返回了简单的文字,现在我们来返回一张照片给客户端,请看如下示例: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.FileInputStream; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestResponsePhoto extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String path=getServletContext().getRealPath("/WEB-INF/ZXM.jpg"); FileInputStream fileInputStream = new FileInputStream(path); ServletOutputStream outputStream = response.getOutputStream(); int len=0; byte [] b=new byte[1024]; while((len=fileInputStream.read(b))!=-1){ outputStream.write(b, 0, len); } outputStream.close(); fileInputStream.close(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } 代码解析如下: 得到文件路径,请参见代码第20行 得到文件输入流,请参见代码第21行 从response中获取到ServletOutputStream作为输出流,请参见代码第22行 将图片返回给客户端,请参见代码第23-29行 运行后,效果如下图所示: 嗯哼,看到了吧:浏览器中显示了从服务端获取的我女朋友的照片 但是,如果想让用户下载这张照片该怎么办呢?请看如下示例: /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ package cn.com; import java.io.FileInputStream; import java.io.IOException; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DownPhoto extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String path=getServletContext().getRealPath("/WEB-INF/zxm.jpg"); System.out.println("-----------------> path="+path); String fileName=path.substring(path.lastIndexOf("\\")+1); fileName=URLEncoder.encode(fileName, "UTF-8"); response.setHeader("content-disposition", "attachment;filename="+fileName); response.setHeader("content-type", "image/jpeg"); FileInputStream fileInputStream = new FileInputStream(path); ServletOutputStream outputStream = response.getOutputStream(); int len=0; byte [] b=new byte[1024]; while((len=fileInputStream.read(b))!=-1){ outputStream.write(b, 0, len); } outputStream.close(); fileInputStream.close(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } } 代码解析如下: 获取到文件名称,请参见代码第23行 设置Header指示客户端下载文件,请参见代码第24行 利用Header设置响应的内容的类型 嗯哼,待用户输入地址后即可下载对应的文件。 除此以外,我们可利用画笔在内存中创作一张图片BufferedImage然后再返回给客户端;有的网站登录时的验证码正是采用该方式实现的。 HttpServletResponse的几个细节问题 getOutputStream()和getWriter()分别用于得到输出字节流和输出字符流的ServletOuputStream、Printwriter。但是请注意:getOutputStream()和getWriter()这两个方法互相排斥,调用了其中任意一个方法后就不能再调用另一方法;否则系统抛出异常。 在Servlet中向ServletOutputStream对象或PrintWriter对象写入的数据将被Servlet引擎(如Tomcat)从response里面获取,然后Servlet引擎再将这些数据当作响应消息的正文且与响应状态行和响应头组合并输出到客户端。这也就是说:并不是response将响应消息传递给了客户端,而是Servlet引擎将响应消息封装到了response中再由Servlet引擎传递给客户端 Serlvet的service()结束后,Servlet引擎将检查getWriter()或getOutputStream()返回的输出流对象是否已经调用过close();如果未关闭则Servlet引擎将调用close()关闭该流对象,如果已经关闭则不作处理

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

后台(10)——Servlet(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有了基础的简单的了解,在深入认识Servlet之前,我们来一起学习HTTP协议。 HTTP简介 HTTP协议(HyperText Transfer Protocol)又叫作超文本传输协议,它是用于从服务器传输超文本到浏览器的传送协议。HTTP不仅保证计算机正确、高效、快速地传输超文本文档还可确定传输文档中的哪一部分内容优先显示。 HTTP是一个应用层协议,一次HTTP通信由请求和响应构成。客户端向服务器发送一个请求,在该请求中包含:请求的方法、URL、用户信息、协议版本、等等信息。服务器在接收到请求后发对此作出响应并返回一个答复消息,该消息包括:响应的时间、请求成功或失败的标识、协议的版本、回复的内容等等信息。 HTTP的特点 标准的HTTP协议是无连接的,无状态的。无连接指的是:每次连接只处理一个请求。服务器处理完客户的请求并收到客户的应答后即断开连接。无状态指的是:协议对于请求的处理没有记忆能力,也就是说每次请求都是独立的,它的执行结果与之前和之后的请求是无直接关系的 标准HTTP协议既有优点也有缺点:优点在于极大地减轻了服务器的压力,每一次请求不会造成不必要连接占用;缺点在于繁复地建立连接和断开连接,请求会传输大量重复的信息,所以随后出现了Keep-Alive、Cookie、Session在某些程度上弥补了标准HTTP的缺点。 HTTP的请求与响应 我们知道:每一次HTTP的请求都由请求(request)和响应(response)构成,在此对这两部分作进一步的说明。 HTTP的请求 HTTP请求由三部分组成:请求消息行、请求消息头、请求消息体 请求消息行 示例如下: GET /HelloWeb/test.html HTTP/1.1 请求消息行包含三部分内容: 请求方式,比如此处的GET 资源URI,比如此处的/HelloWeb/test.html 协议及其版本号,比如此处的HTTP/1.1 请求消息头 示例如下: Host:localhost Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8 Accept-Charset: UTF-8 Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.6 Cache-Control: max-age=0 Cookie:JSESSIONID=97C4302F3350676F65B5E4409ABA87CF Referer: http://blog.csdn.net/lfdfhl Content-Type:application/x-www-form-urlencoded If-Modified-Since: Wed, 02 Feb 2011 12:04:56 GMT User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.130 Safari/537.36 Connection: keep-alive Date: Tue, 15 Nov 2017 01:12:31 GMT 请求消息头中内容较多,现将常用和重要的字段介绍如下: Host:发起请求的主机名及其端口号 Accept:客户端可接收的文档类型。其中,*/*表示可接收任何类型 Accept-Charset: 客户端可接受的字符编码集 Accept-Encoding: 客户端支持的压缩格式 Accept-Language:客户端可接受的语言 Cache-Control:设置请求和响应遵循的缓存机制 Cookie:HTTP请求发送时会把保存在该请求域名下的所有cookie值一起发送至服务器。 Referrer:发起HTTP请求的页面的URL Content-Type:请求时所传递的内容的类型 Content-Length:请求时所传递的内容的长度 If-Modified-Since:该值与响应消息头的Last-Modified字段相对应。Last-Modified与If-Modified-Since都是用来记录页面的最后修改时间。当客户端访问页面时,服务器会将页面最后修改时间通过Last-Modified由服务器发往客户端,客户端会记录下该值;当客户端再次发起请求时,客户端会通过 If-Modified-Since将此前服务器端发过来的最后修改时间戳发送回去;服务器通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的则返回新的内容,如果是最新的则返回304告诉客户端其本地cache的页面是最新的,于是客户端就可直接从本地加载页面。 User-Agent:表示发出该请求的客户端的相关信息,比如操作系统及版本、CPU类型、浏览器及版本、浏览器渲染引擎、浏览器语言等等 Connection: 表示是否需要持久连接,HTTP 1.1默认进行持久连接。 Date: 请求发送的日期和时间 Range:用于告知服务器只需返回部分内容,故用该Range描述这部分内容的范围;该字段对于断点续传等功能非常实用 其实,从这里可以看出来:在每次请求时,客户端需要告诉服务器:自身支持的字符集,压缩格式,语言;请求的消息内容,长度等等众多信息,从而尽量清楚地表达自身的条件和需求以便服务器做出相应的响应。 请求消息体 username=大泽玛利亚&hobby=摄影 当请求方式是POST方式时可见消息正文,假若是GET方式则请求消息体中无内容 HTTP的响应 HTTP响应由三部分组成:响应消息行、响应消息头、响应消息体 响应消息行 HTTP/1.1 200 OK 响应消息行由三部分组成: 协议及其版本号,比如此处的 HTTP/1.1 响应状态码,比如此处的200 常用的状态码有:200(正常)、02/307(临时重定向)、304(未修改)表示客户端缓存的版本是最新的,客户端无需到服务器请求、404(找不到)、500(服务器内部错误) 响应码的描述,比如此处的OK 响应消息头 Accept-Ranges: bytes Content-Encoding: gzip Content-Length: 4533 Content-Language: en,zh Content-Type: text/html Date: Sun, 06 Sep 2015 07:56:07 GMT Last-Modified: Fri, 04 Sep 2015 13:37:55 GMT Server: apache tomcat Location: http://blog.csdn.net/lfdfhl Refresh: 5; url=http://www.csdn.net/ Content-Disposition: attachment; filename=test.zip Set-Cookie: UserID=tom; Max-Age=3600; Version=1 Expires: Thu, 01 Dec 2015 12:20:00 GMT Cache-Control: no-cache Pragma: no-cache Connection: keep-alive 响应消息头中内容较多,现将常用和重要的字段介绍如下: Accept-Ranges: 表明服务器是否支持指定范围请求及哪种类型的分段请求。假若服务器想告诉浏览器不要使用Range,则返回Accept-Range: none;假若服务器想告诉浏览器可使用以byte为单位的Range的请求,则返回Accept-Range:bytes Content-Encoding: 服务器的返回内容的压缩编码类型 Content-Length: 服务器的返回内容的的长度 Content-Language: 服务器的返回内容的语言 Content-Type: 服务器的返回内容的类型 Date:服务器发出响应的时间 Last-Modified: 返回的内容的最后修改时间 Server: 服务器的类型 Location:指示被请求的资源的位置,常和请求消息头一起使用完成请求重定向 Refresh:延时跳转到某个页面或者定时刷新本页面 Content-Disposition: 指示客户端下载文件 Set-Cookie: 服务器端发送给客户端的Cookie Expires: 响应过期的时间 Cache-Control: 指定响应遵循的缓存机制 Pragma: 用来包含实现特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache-Control:no-cache相同 Connection: 表示是否需要持久连接,HTTP 1.1默认进行持久连接。 响应消息体 响应消息体中表示响应的的具体内容。比如,响应的内容是网页,那么响应消息体的内容和网页右键”查看网页源代码”所看到的内容一样。 后会有期 在此简单地介绍了HTTP协议,但也不会如此仓促地完结。我们将在后续的博客中结合Servlet对与HTTP紧密相关的Cookie和Session进行详细的学习,再会。

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

后台(05)——MySQL(5)

探索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 本文简介 在之前的博客中我们学习了MySQL的DDL、DML、DCL、DQL;还有数据的完整性、多表查询。在这篇博客中我们将一起学习MySQL中的函数、MySQL数据库的备份与恢复。 MySQL中的函数 MySQL提供了不少自带的函数,在此简要介绍,时间函数,字符串函数,数学函数。 时间函数 SELECT NOW(); SELECT DAY (NOW()); SELECT DATE (NOW()); SELECT TIME (NOW()); SELECT YEAR (NOW()); SELECT MONTH (NOW()); SELECT CURRENT_DATE(); SELECT CURRENT_TIME(); SELECT CURRENT_TIMESTAMP(); SELECT ADDTIME('14:23:12','01:02:01'); SELECT DATE_ADD(NOW(),INTERVAL 1 DAY); SELECT DATE_ADD(NOW(),INTERVAL 1 MONTH); SELECT DATE_SUB(NOW(),INTERVAL 1 DAY); SELECT DATE_SUB(NOW(),INTERVAL 1 MONTH); SELECT DATEDIFF('2013-12-30','2013-12-20'); 这些时间函数与Java中Date类提供的函数非常类似,故在此不再赘述,欲知其意观其名即可。 字符串函数 SELECT CONCAT ('星爷','9527'); SELECT INSTR ('星爷9527','9527'); SELECT LENGTH('本文作者:http://blog.csdn.net/lfdfhl'); 这些字符串函数与Java中String类提供的函数非常类似,故在此不再赘述,欲知其意观其名即可。 数学函数 SELECT BIN(2); SELECT ABS(-136); SELECT FLOOR(3.14); SELECT CEILING(3.14); 这些数学函数与Java中Math类提供的函数非常类似,故在此不再赘述,欲知其意观其名即可。 数据库的备份与恢复 在此简要介绍MySQL数据库的备份与恢复 MySQL数据库的备份 在DOS中使用mysqldump命令可以生成指定数据库的脚本文本,语法如下: mysqldump –u用户名 –p密码 数据库名>生成的脚本文件路径 但是请注意:脚本文本中只包含数据库的内容,而不存在创建数据库的语句!所以在恢复数据时需要自已手动创建一个数据库,然后再去恢复数据。 在此,备份这几天使用的数据库db1到D盘: C:\Users\lf>mysqldump -uroot -proot db1>d:\db1.sql 即下图所示: MySQL数据库的恢复 在DOS中使用source命令可执行数据库的恢复,语法如下: source 数据库脚本文件路径 再次提醒: 在恢复之前必须先创建数据库或者使用已有的数据库 在此,将刚才导出的数据库脚本恢复到新的数据库db2: mysql> create database db2; mysql> use db2; mysql> source d:\db1.sql 也可参见下图: 至此,关于MySQL的基础知识就全部结束完了,谢谢。

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

后台(02)——MySQL(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 SQL简述 Structure Query Language(结构化查询语言)简称SQL,它被美国国家标准局(ANSI)确定为关系型数据库语言的美国标准,后被国际化标准组织(ISO)采纳为关系数据库语言的国际标准。数据库管理系统可以通过SQL管理数据库;定义和操作数据,维护数据的完整性和安全性 SQL的优点 简单易学,具有很强的操作性 绝大多数重要的数据库管理系统均支持SQL 高度非过程化;用SQL操作数据库时大部分的工作由DBMS自动完成 SQL的分类 DDL(Data Definition Language) 数据定义语言,用来操作数据库、表、列等; 常用语句:CREATE、 ALTER、DROP DML(Data Manipulation Language) 数据操作语言,用来操作数据库中表里的数据; 常用语句:INSERT、 UPDATE、 DELETE DCL(Data Control Language) 数据控制语言,用来操作访问权限和安全级别; 常用语句:GRANT、DENY DQL(Data Query Language) 数据查询语言,用来查询数据 常用语句:SELECT 在此,请注意区分DDL和DML: 它们两者的作用对象和级别不一样。DDL操作的对象是数据库,或者一张表,或者表中的某列;DML操作的是表里的数据。 在了解完这些基础知识之后,我们来依次详细学习DDL、DML、DCL、DQL DDL 创建数据库 create database db1; 创建名字为db1的数据库 show create database db1; 查看刚才创建的数据库db1,结果如下: | Database | Create Database | db1 | CREATE DATABASE db1 /!40100 DEFAULT CHARACTER SET utf8 /** 从这里可以看出,刚才创建的数据库采用的是utf8作为字符集。 当然,我们还可以在创建数据库时为其指定字符集 create database db2 character set gbk; 查询数据库 show databases; 查询出所有的数据库 删除数据库 drop database db2; 其实,从这也可以看出来创建数据库和删除数据库是非常类似的,只不过它们的关键是不同;前者使用的是create后者是drop 修改数据库 alter database db1 character set gbk; 将数据库db1的字符集修改为gbk 切换数据库 use db1; 表示现在开始使用数据库db1 查看当前使用的数据库 select database(); 请注意该语句最后有个括号() 创建表 语法如下: create table 表名( 字段1 字段类型, 字段2 字段类型, …………… 字段n 字段类型 ); 示例,创建一张员工表: 在此创建一张员工表,包含了员工的基本信息。 查看当前数据库中的所有表 show tables; 查看刚才创建的表 show create table employee; 查看表的字段信息 describe employee; 也可以简写为: desc employee; 修改表的字符集 alter table employee character set gbk; 为表增加列 alter table employee add column photo blob; 为表添加了数据类型为blob的列photo 也可以简写为: alter table employee add photo blob; 修改列的长度 alter table employee modify job varchar(170); 将表中job字段的长度修改为170 修改列的名称 alter table employee change name username varchar(100); 将表中原name改名为username 删除列 alter table employee drop photo; 删除表中的photo列 修改表的名字 rename table employee to user; 删除表 drop table user; DML DML用于对表中的数据进行增、删、改的操作。常用的语句有INSERT 、UPDATE、 DELETE 嗯哼,我们先创建一张表 create table employee( id int, username varchar(100), gender varchar(10), birthday date, salary float(10,2), entry_date date, resume text ); 插入操作:INSERT INSERT的语法: INSERT INTO 表名(列名1,列名2 …)VALUES(列值1,列值2…); 请注意: 列名与列值的类型、个数、顺序要一一对应 列值不要超出列定义的长度 如果插入空值,请使用null 插入的日期和字符需用引号括起来,例如:’sun’、’2016-09-04’ INSERT的示例: INSERT INTO employee (id,username,gender,birthday,salary,entry_date,RESUME) VALUES (1,’大泽玛利亚’,’female’,’1990-09-12’,20000.00,’2010-11-22’,’beauty’); INSERT INTO employee (id,username,gender,birthday,salary,entry_date,RESUME) VALUES (2,’武藤兰姐姐’,’female’,’1980-09-12’,30000.00,’2000-12-12’,’good’); INSERT INTO employee (id,username,gender,birthday,salary,entry_date,RESUME) VALUES (3,’井空苍妹妹’,’female’,’1987-07-28’,50000.00,’2001-08-09’,’great’); 当然,也可以批量插入数据: INSERT INTO employee VALUES (4,’杉原杏璃’,’female’,’1992-04-01’,60000.00,’2014-09-03’,’very good’), (5,’佐佐木希’,’female’,’1993-05-09’,70000.00,’2013-04-04’,’very nice’), (6,’伊藤梅子’,’female’,’1995-11-07’,80000.00,’2012-03-05’,’very sexy’); 修改操作:UPDATE UPDATE的语法: UPDATE 表名 SET 列名1=列值1 , 列名2=列值2…..WHERE 列名=值 UPDATE的示例: UPDATE employee SET salary=88000; 将表中所有员工的salary修改为88000 UPDATE employee SET salary=99000 WHERE username=’大泽玛利亚’; 将表中username为大泽玛利亚的员工的salary修改为99000 UPDATE employee SET salary=69000,birthday=’1993-02-28’ WHERE username=’井空苍妹妹’; 将表中username为井空苍妹妹的员工的salary修改为69000、birthday修改为1993-02-28 UPDATE employee SET salary=salary+1000 WHERE username=’佐佐木希’; 将表中username为佐佐木希的员工的salary增加1000 删除操作:DELETE DELETE的语法: DELETE FROM 表名 WHERE 列名=值 DELETE的示例: DELETE FROM employee WHERE username=’大泽玛利亚’; 将表中username为大泽玛利亚的员工删除 DELETE FROM employee; 使用DELETE将表中所有数据删除,执行该操作后表结构还存在,删除后的数据可以找回 TRUNCATE TABLE employee; 使用TRUNCATE将表中所有数据删除,执行该操作后系统将该表DROP然后再创建一个同样的新表,其执行速度远快于DELETE;但是请注意:该方式删除的数据不能找回。 DCL 之前我们说过:DCL(数据控制语言)用来定义访问权限和安全级别;在此对其进行简单的介绍 创建用户 创建用户的语法为: create user 用户名@IP地址 identified by 密码; 请看如下示例: create user xy@loaclhost identified by ‘123456’; 在此创建一个新用户,用户名为xy密码是123456 请注意,创建新用户后需要执行命令更新权限表(grant tables) FLUSH PRIVILEGES; 给用户授权 给户授权的语法为: grant 权限1,权限2,……..,权限n on 数据库名.* to 用户名@IP地址 identified by ‘密码’; 如果将操作数据库的所有的权限授予用户,语法为: grant all on 数据库名.* to 用户名@IP地址 identified by ‘密码’; 请看如下示例: grant all on db1.* to xy@localhost identified by ‘123456’; 撤销授权 撤销授权的语法为: revoke 权限1,权限2,……..,权限n on 数据库名.* from 用户名@IP地址; 如果撤销用户拥有的某数据库的全部权限,语法为: revoke all on db1.* from xy@localhost; 查看用户权限 查看用户权限的语法为: show grants for 用户名@IP地址; 请看如下示例: show grants for xy@localhost; 删除用户 删除用户权限的语法为: drop user 用户名@IP地址; 请看如下示例: drop user xy@localhost;

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

后台(03)——MySQL(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 DQL 在上一篇博客中我们学习了DDL、DML、DCL在本篇博客中我们将着重讨论MySQL中非常重要的DQL。 数据库执行DQL语句并不会对数据进行改变,而是从数据库返回结果集给客户端;该结果集是一张存在于内存的虚拟表。 DQL语法: SELECT 列名 FROM 表名【WHERE—GROUP BY—HAVING—ORDER BY】 在正式进入这部分之前,我们先准备一下稍后会用到的数据。 CREATE TABLE student ( sid CHAR(6), sname VARCHAR(50), age INT, gender VARCHAR(50) ); 创建学生表student INSERT INTO student VALUES(‘S_1001’, ‘liuYi’, 14, ‘male’); INSERT INTO student VALUES(‘S_1002’, ‘chenEr’, 15, ‘female’); INSERT INTO student VALUES(‘S_1003’, ‘zhangSan’, 13, ‘male’); INSERT INTO student VALUES(‘S_1004’, ‘liSi’, 16, ‘female’); INSERT INTO student VALUES(‘S_1005’, ‘wangWu’, 17, ‘male’); INSERT INTO student VALUES(‘S_1006’, ‘zhaoLiu’, 18, ‘female’); INSERT INTO student VALUES(‘S_1007’, ‘sunQi’, 13, ‘male’); INSERT INTO student VALUES(‘S_1008’, ‘zhouBa’, 15, ‘female’); INSERT INTO student VALUES(‘S_1009’, ‘wuJiu’, 11, ‘male’); INSERT INTO student VALUES(‘S_1010’, ‘zhengShi’, 15, ‘female’); INSERT INTO student VALUES(‘S_1011’, ‘xxx’, NULL, NULL); 向学生表student中插入数据。 CREATE TABLE emp( empno int, ename varchar(50), job varchar(50), mgr int, hiredate date, sal decimal(7,2), comm decimal(7,2), deptno int ); 建立员工表emp INSERT INTO emp values(7369,’SMITH’,’CLERK’,7902,’1980-12-17’,800,NULL,20); INSERT INTO emp values(7499,’ALLEN’,’SALESMAN’,7698,’1981-02-20’,1600,300,30); INSERT INTO emp values(7521,’WARD’,’SALESMAN’,7698,’1981-02-22’,1250,500,30); INSERT INTO emp values(7566,’JONES’,’MANAGER’,7839,’1981-04-02’,2975,NULL,20); INSERT INTO emp values(7654,’MARTIN’,’SALESMAN’,7698,’1981-09-28’,1250,1400,30); INSERT INTO emp values(7698,’BLAKE’,’MANAGER’,7839,’1981-05-01’,2850,NULL,30); INSERT INTO emp values(7782,’CLARK’,’MANAGER’,7839,’1981-06-09’,2450,NULL,10); INSERT INTO emp values(7788,’SCOTT’,’ANALYST’,7566,’1987-04-19’,3000,NULL,20); INSERT INTO emp values(7839,’KING’,’PRESIDENT’,NULL,’1981-11-17’,5000,NULL,10); INSERT INTO emp values(7844,’TURNER’,’SALESMAN’,7698,’1981-09-08’,1500,0,30); INSERT INTO emp values(7876,’ADAMS’,’CLERK’,7788,’1987-05-23’,1100,NULL,20); INSERT INTO emp values(7900,’JAMES’,’CLERK’,7698,’1981-12-03’,950,NULL,30); INSERT INTO emp values(7902,’FORD’,’ANALYST’,7566,’1981-12-03’,3000,NULL,20); INSERT INTO emp values(7934,’MILLER’,’CLERK’,7782,’1982-01-23’,1300,NULL,10); 向员工表emp中插入数据 CREATE TABLE dept( deptno INT, dname varchar(14), loc varchar(13) ); 建立部门表dept INSERT INTO dept values(10, ‘ACCOUNTING’, ‘NEW YORK’); INSERT INTO dept values(20, ‘RESEARCH’, ‘DALLAS’); INSERT INTO dept values(30, ‘SALES’, ‘CHICAGO’); INSERT INTO dept values(40, ‘OPERATIONS’, ‘BOSTON’); 向部门表dept中插入数据 基本查询 查询所有列 SELECT * FROM student; 查询指定列 SELECT sid, sname, age FROM student; 条件查询 在进行条件查询时需在WHERE子句使用以下运算符和关键字: =、!=、<、<=、>、>= BETWEEN…AND IN(value1,value2,….valueN) NOT IN(value1,value2,….valueN) IS NULL IS NOT NULL AND OR NOT 请看如下示例: 查询性别为女,并且年龄小于20的记录 SELECT * FROM student WHERE gender = ‘female’ AND age<20; 查询学号为S_1001或者姓名为liSi的记录 SELECT * FROM student WHERE sid=’S_1001’ OR sname=’liSi’; 查询学号为S_1001,S_1002,S_1003的记录 SELECT * FROM student WHERE sid IN (‘S_1001’,’S_1002’,’S_1003’); 查询学号不为S_1001,S_1002,S_1003的记录 SELECT * FROM student WHERE sid NOT IN (‘S_1001’,’S_1002’,’S_1003’); 查询年龄为null的记录 SELECT * FROM student WHERE age IS NULL; 查询姓名不为null的记录 SELECT * FROM student WHERE sname IS NOT NULL; 查询年龄在14到16之间的记录 SELECT * FROM student WHERE age>=14 AND age<=16; SELECT * FROM student WHERE age BETWEEN 14 AND 16; 查询性别非男的记录 SELECT * FROM student WHERE gender !=’male’; SELECT * FROM student WHERE NOT gender =’male’; 模糊查询 模糊查询常使用关键字LIKE 通配符_表示任意一个字符 通配符%表示任意0—N个字符 请看如下示例: 查询姓名由5个字母构成的记录 SELECT * FROM student WHERE sname LIKE “_____”; 查询姓名由5个字母构成且第5个字母为i的记录 SELECT * FROM student WHERE sname LIKE “____i”; 查询姓名以“z”开头的记录 SELECT * FROM student WHERE sname LIKE “z%”; 查询姓名中第2个字母为i的记录 SELECT * FROM student WHERE sname LIKE “_i%”; 查询姓名中包含a字母的记录 SELECT * FROM student WHERE sname LIKE “%a%”; 字段控制查询 请看如下示例: 利用DISTINCT去除重复记录 SELECT DISTINCT job FROM emp; 利用函数IFNULL把NULL转换成数值0 SELECT IFNULL(comm,0) FROM emp; 查看雇员的月薪与佣金之和 SELECT sal+IFNULL(comm,0) FROM emp; 利用关键字AS给列名添加别名 SELECT sal+IFNULL(comm,0) AS total FROM emp; SELECT sal AS salary ,ename AS NAME FROM emp; 在使用AS给列名添加别名,可空格代替AS;但不推荐这么做。 排序 常用的两种排序方式 ORDER BY 列名 ASC ORDER BY 列名 DESC 请看如下示例: 查询所有学生记录,按年龄降序排序 SELECT * FROM student ORDER BY age DESC; 查询所有雇员,按月薪降序排序,若月薪相同时按员工编号降序排序 SELECT * FROM emp ORDER BY sal DESC,empno DESC; 聚合函数 聚合函数用于纵向(即列)运算;它具有自动滤空的功能,若某一个值为NULL,那么会自动将其过滤使其不参与运算。 常用的聚合函数如下: COUNT( ):统计指定列其值不为NULL的记录行数 MAX( ):计算指定列的最大值,如果指定列是字符串类型则使用字符串排序运算 MIN( ):计算指定列的最小值,如果指定列是字符串类型则使用字符串排序运算 SUM( ):计算指定列的数值和,如果指定列类型不是数值类型则计算结果为0 AVG( ):计算指定列的平均值,如果指定列类型不是数值类型则计算结果为0 请看如下示例: 查询emp表中记录数 SELECT COUNT(*) FROM emp; 查询emp表中有佣金的人数 SELECT COUNT(comm) AS total FROM emp; 查询emp表中月薪大于2000的人数 SELECT COUNT(*) FROM emp WHERE sal>2000; 查询月薪与佣金之和大于2000的人数 SELECT COUNT(*) FROM emp WHERE (sal+IFNULL(comm,0))>2000; 查询有佣金的人数,有领导的人数 SELECT COUNT(comm), COUNT(mgr) FROM emp; 查询所有雇员月薪的总和 SELECT SUM(sal) FROM emp; 查询所有雇员月薪和,以及所有雇员佣金之和 SELECT SUM(sal) , SUM(comm) FROM emp; 统计所有员工平均工资 SELECT AVG(sal) FROM emp; 查询所有员工中的最高工资 SELECT MAX(sal) FROM emp; 查询所有员工中的最低工资 SELECT MIN(sal) FROM emp; 分组查询 当分组查询时需使用GROUP BY子;例如,查询每个部门的工资总和,此时需用部门来进行分组 请看如下示例: 查询每个部门的部门编号和每个部门的工资和 SELECT deptno,SUM(sal) FROM emp GROUP BY deptno; 查询每个部门的部门编号以及每个部门的人数 SELECT deptno,COUNT(*) FROM emp GROUP BY deptno; 查询每个部门的部门编号以及每个部门工资大于2000的人数 SELECT deptno,COUNT(*) FROM emp WHERE sal>2000 GROUP BY deptno; 请务必注意: 在MySQL中使用SQL时,如果某列名和聚合函数同时出现在了SELECT与FROM之间,那么该列名一定要写在group by 之后。 还是来看刚才的例子: 查询每个部门的部门编号和每个部门的工资和,SQL语句如下: SELECT deptno,SUM(sal) FROM emp GROUP BY deptno; 如果按照下面的写法: SELECT ename,COUNT(*) FROM emp GROUP BY deptno; 在MySQL中执行时不会报错,但是查询出来的结果明显不对,稀奇古怪的样子;而且该写法在其他数据库中执行时会报错! 关于这个注意事项需要多加体会。 HAVING子句 HAVING子句用于在GROUP BY分组之后对数据再次筛选。 请看如下示例: 查询工资总和大于10000的部门编号以及工资和 SELECT deptno, SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal) >10000; LIMIT LIMIT用来限定查询结果的起始行和总行数,常用于分页。 请看如下示例: 从student表中查询5行记录,起始行从2开始 SELECT * FROM student LIMIT 2, 5; 查询代码的书写顺序和执行顺序 查询语句的书写顺序: select – from – where – group by – having – order by – limit 查询语句的执行顺序: from – where – group by – having - select - order by – limit

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

Laravel 前后台共享数据

在视图模板中初始化JS变量。 <script> var app = <?php echo json_encode($array); ?>; </script> 5.5以后可以这么写, 用 @json Blade 指令替代手动 json_encode <script> var app = @json($array); </script> 曾经在多语言项目中这么用过。 <script> window.Laravel = { csrfToken: '{{ csrf_token() }}', Locale: '<?php echo \App::getLocale(); ?>', Languages: <?php echo json_encode( [ 'scaffold' => __('scaffold::t'), 'module_dashboard' => __('module_dashboard::t'), 'module_user' => __('module_user::t'), 'setting' => __('setting::t'), ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);?> }; </script> Laravel变量传入在vue组件中 定义组件 <script> export default { props: ['surveyData'], mounted () { // Do something useful with the data in the template console.dir(this.surveyData) } } </script> 注入变量 <survey-component :survey-data="'{!! json_encode($surveyData) !!}'"></survey-component> 参考:https://medium.com/@m_ramsden/passing-data-from-laravel-to-vue-98b9d2a4bd23https://laravel-china.org/docs/laravel/5.6/blade/1375

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

后台(38)——SqlMapConfig.xml

探索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的示例中我们采用SqlMapConfig.xml配置数据库连接池和管理mapper.xml,今天我们来继续学习SqlMapConfig.xml常用的其他配置。 SqlMapConfig.xml中配置的内容和顺序如下: properties settings typeAliases typeHandlers objectFactory plugins environments environment transactionManager dataSource mappers 在此,介绍几个常用的。 properties 我们可将一些配置信息专门写在对应的配置文件中,然后在SqlMapConfig.xml引用即可。比如,将数据库配置信息置于db.properties中: driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mb?characterEncoding=utf-8 username=root password=root 然后在SqlMapConfig.xml中引用 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="db.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="sqlmap/StudentMapper.xml" /> </mappers> </configuration> 引入db.properties,请参见代码第4行 使用db.properties中的内容,请参见代码第9—12行 setting 可在SqlMapConfig.xml中利用setting配置全局参数从而作用于MyBatis的行为 <settings> <setting name="cacheEnabled" value="true" /> <setting name="lazyLoadingEnabled" value="true" /> <setting name="multipleResultSetsEnabled" value="true" /> <setting name="useColumnLabel" value="true" /> <setting name="useGeneratedKeys" value="false" /> <setting name="autoMappingBehavior" value="PARTIAL" /> <setting name="defaultExecutorType" value="SIMPLE" /> <setting name="defaultStatementTimeout" value="25" /> <setting name="safeRowBoundsEnabled" value="false" /> <setting name="mapUnderscoreToCamelCase" value="false" /> <setting name="localCacheScope" value="SESSION" /> <setting name="jdbcTypeForNull" value="OTHER" /> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" /> </settings> 关于这些setting的具体作用,请官方文档,在此不再赘述 typeAliases typeAliases可为Java类型设置一个短的名字从而减少类完全限定名的冗余. MyBatis已经为许多常见的Java类型内建了相应的类型别名,如下所示: 在mapper.xml中会定义很多的statement,每个statement需要利用parameterType指定输入参数的类型、利用resultType指定输出结果的映射类型。如果在指定类型时输入类型全路径会非常的繁琐,所以我们可利用typeAliases为这些类指定别名,从而提高开发效率 比如,我们可以为单个类指定别名 <typeAliases> <typeAlias type="cn.com.Student" alias="Student" /> </typeAliases> 所以在mapper.xml中将parameterType指定为Student即可 <insert id="insertStudent" parameterType="Student"> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO student (name,gender,birthday) value (#{name},#{gender},#{birthday}) </insert> 当然,我们还可以为某个包下所有类指定别名。 <typeAliases> <package name="cn.com"/> </typeAliases> 这些包下的类名所对应的别名就不再是全路径了,而是java文件本身的名字了。比如cn.com.Student的别名就是Student typeHandlers 无论是MyBatis在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用typeHandlers类型处理器将获取的值以合适的方式进行转换。简单地说:MyBatis中通过typeHandlers完成JDBC类型和Java类型的转换。Mybatis默认为我们实现了许多TypeHandler, 当我们没有配置指定TypeHandler时,Mybatis会根据参数或者返回结果的不同为我们选择合适的TypeHandler进行数据转换处理。 mappers mappers用于配置SQL映射文件 第一种方式 <mappers> <mapper resource="sqlmap/StudentMapper.xml" /> </mappers> 利用resource加载单个映射文件,我们在MyBatis的入门示例中就是如此配置的。 第二种方式 通过mapper接口(mapper.java)加载单个映射文件(mapper.xml) <mappers> <mapper class="cn.com.StudentMapper"/> </mappers> 利用该方式配置mapper时务必注意:必须将xxxmapper.xml和xxxmaper.java置于同一个包下,且文件名必须一致。 第三种方式 批量配置mapper <mappers> <package name="cn.com"/> </mappers> 配置一个包中的mapper。利用该方式配置mapper时务必注意:必须将xxxmapper.xml和xxxmaper.java置于同一个包下,且文件名必须一致。

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

后台(07)——XML和JUnit

探索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 本文简介 本文主要介绍XML及其常用的解析方式和JUnit单元测试 XML简介 eXtensible Markup Language简称XML,它是一门可扩展标记语言;之所以称其为可扩展语言,是因为XML的标签都是自定义的。与HTML用于数据展示不同,XML主要用于数据的存储,比如Web开发中的众多配置文件都是由XML实现的。除了作用不一样以外,XML较HMTL而言语法也更加严格。 现在,我们来看一个非常简单的XML文件 <?xml version="1.0" encoding="UTF-8"?> <students> <student number="1"> <name>空空苍井</name> <age>23</age> <address>东京</address> </student> <student number="2"> <name>小泽玛丽</name> <age>22</age> <address>大阪</address> </student> <student number="3"> <name>杉原杏璃</name> <age>19</age> <address>仙台</address> </student> </students> 在该示例中定义了根标签<students></students>然后在里面放了三个<student></student>标签用于表示每一个学生的信息;其中每个学生又包括了name,age,address 请注意XML的书写规范: 将<?xml version=”1.0” encoding=”UTF-8”?>置于XML文档第一行 XML文档中必须有且仅有有一个根元素 XML文档中的元素需要正确闭合 XML文档中的元素需要正确嵌套 XML文档中的元素名称区分大小写 XML文档中的属性值必须用引号引起来 XML的约束 我们可以通过XML的约束来限制XML内容的书写,就像在Java中为集合指定了泛型来约束存入集合中的数据一样;我们可在约束文档定义在XML中允许出现的元素名称、属性及元素出现的顺序等等。XML中常用的约束有DTD和Schema,现在分别介绍。 DTD DTD(Document Type Definition)文档类型定义,请看如下示例: <!ELEMENT students (student*) > <!ELEMENT student (name,age,address)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT address (#PCDATA)> <!ATTLIST student number ID #REQUIRED> 在此定义一个.dtd文件,在该文件中约束了xml的元素和属性。 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE students SYSTEM "studentDTD.dtd"> <students> <student number="number1"> <name>空空苍井</name> <age>23</age> <address>东京</address> </student> <student number="number2"> <name>小泽玛丽</name> <age>22</age> <address>大阪</address> </student> <student number="number3"> <name>杉原杏璃</name> <age>19</age> <address>仙台</address> </student> </students> 我们在该XML文件中使用刚才定义的DTD文件,请参见第2行代码。此时,我们假如写了DTD中未声明的标签就会报错;类似地,其他未遵守DTD文件的写法也会报错。其实,利用DTD文件约束XML的方式还是有些呆板,可读性也不强。所以,请看下面的Schema约束。 Schema Schema也是一种用于定义和描述XML文档结构与内容的模式语言,其出现是为了优化DTD的局限性。请看如下示例: <?xml version="1.0"?> <xsd:schema xmlns="http://www.stay4it.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.stay4it.com" elementFormDefault="qualified"> <xsd:element name="students" type="studentsType" /> <xsd:complexType name="studentsType"> <xsd:sequence> <xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="studentType"> <xsd:sequence> <xsd:element name="name" type="xsd:string" /> <xsd:element name="age" type="ageType" /> <xsd:element name="gender" type="genderType" /> </xsd:sequence> <xsd:attribute name="number" type="numberType" use="required" /> </xsd:complexType> <xsd:simpleType name="genderType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="male" /> <xsd:enumeration value="female" /> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="ageType"> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="0" /> <xsd:maxInclusive value="130" /> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="numberType"> <xsd:restriction base="xsd:string"> <xsd:pattern value="stay4it_\d{3}" /> </xsd:restriction> </xsd:simpleType> </xsd:schema> 在此定义一个.xsd文件,在该文件中约束了xml的元素和属性。请注意,在该文件中的限制条件非常细致。比如:限制了元素的类型,取值范围,出现次数等。 <?xml version="1.0" encoding="UTF-8"?> <students xmlns="http://www.stay4it.com" xsi:schemaLocation="http://www.stay4it.com studentSchema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <student number="stay4it_101"> <name>空空苍井</name> <age>23</age> <gender>female</gender> </student> <student number="stay4it_102"> <name>小泽玛丽</name> <age>22</age> <gender>female</gender> </student> <student number="stay4it_103"> <name>杉原杏璃</name> <age>19</age> <gender>female</gender> </student> </students> 在该XML文档中采用刚才定义的Schema约束XML的书写。同样地,如果所书写的XML代码违反了该Schema约束那么会报错。 XML文档的解析方式 常用的解析XML文档的方式有DOM解析和SAX解析。 DOM解析 将XML文档加载进内存形成一颗DOM树(document对象)并将文档的各个组成部分封装为对象。所以,可以对DOM树进行增删改查。但是DOM树非常占内存,解析速度较慢,故DOM解析不适合较为复杂的XML文件。 如果说Java是面向对象编程,那么DOM是面向节点编程 1 、整个XML文档就是一个文档(Document)节点。 2 、文档中每个元素是也是一个元素(Element)节点 3 、元素中的文字则是文本(Text)节点。 4 、元素的属性是属性(Attr)节点。 5 、标签之间的空格换行也是节点! 6 、总之,XML文档中的每个成分都是一个节点 由此可见,XML文档中每一个组成部分都是节点。所以,元素一定是节点,而节点不一定是元素。 SAX解析 相比于DOM,SAX是一种速度更快,更有效的方法。SAX基于事件驱动,它逐行读取文档,一边读取一边解析,所以该方式占内存非常小,速度很快。而且在解析过程的任意时刻均可停止解析,但是该方式只能读取XML不能回写。 在开发中常用DOM4J和XPATH解析XML文件,先对其分别介绍。 利用DOM4J解析XML 请看如下示例: package cn.xml; import java.util.List; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.SAXReader; import org.junit.Test; /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ public class TestDOM4J { @Test public void testDOM4J01() throws DocumentException{ SAXReader reader = new SAXReader(); Document document = reader.read("src/student.xml"); Element rootElement = document.getRootElement(); List<Element> elementList = rootElement.elements(); int elementSize=elementList.size(); int nodeCount=rootElement.nodeCount(); System.out.println("根节点一共有"+elementSize+"个子元素"); System.out.println("根节点一共有"+nodeCount+"个子节点"); } @Test public void testDOM4J02() throws DocumentException{ SAXReader reader = new SAXReader(); Document document = reader.read("src/student.xml"); Element rootElement = document.getRootElement(); analyzeElement(rootElement); } private void analyzeElement(Element element) { int nodeCount=element.nodeCount(); for (int i = 0; i < nodeCount; i++) { Node node = element.node(i); if(node instanceof Element){ Element elem=(Element) node; String elementName=elem.getName(); List<Attribute> attrivuteList=elem.attributes(); int attributeSize=attrivuteList.size(); System.out.println(elementName+"有属性"+attributeSize+"个"); for(int j=0;j<attributeSize;j++){ Attribute attribute=attrivuteList.get(j); String attributeName=attribute.getName(); String attributeText=attribute.getText(); System.out.println(elementName+"有属性:"+attributeName+",其值为:"+attributeText); } analyzeElement(elem); System.out.println(elementName+"是元素Element"); }else{ String nodeText=node.getText(); System.out.println(nodeText+"文本是节点Node"); } System.out.println("-------------------"); } } } 在该示例中展示了利用DOM4J加载XML,并解析出XML中的元素和节点且获取出元素的名称,节点的文本,属性的值等等内容。在此,务必注意区分元素和节点;请切记:标签之间的空格换行也是一个节点!!!!至于,DOM4J的其他API在此不在依次举出。 当你看完这个例子,如果还不了解元素和节点的区别,请您参照w3school的教程 利用XPATH解析XML XPATH的全称是Xml Path Language;专门用于查询XML中的数据。怎么查询呢?嗯哼,其实从它的全名可以就能看出点端倪了:该方式和路径是相关联的。 请看如下示例: package cn.xml; import java.util.List; import org.dom4j.Document; import org.dom4j.Node; import org.dom4j.io.SAXReader; import org.junit.Test; /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ public class TestXPATH { @Test public void testXPATH1() throws Exception{ SAXReader read = new SAXReader(); Document document = read.read("src/student.xml"); Node node = document.selectSingleNode("/students/student[1]/name"); String text=node.getText(); System.out.println(text); } @Test public void TESTXPATH2() throws Exception{ SAXReader read = new SAXReader(); Document document = read.read("src/student.xml"); List<Node> nodeList = document.selectNodes("//*"); for (int i = 0; i < nodeList.size(); i++) { Node node = nodeList.get(i); String name=node.getName(); String text=node.getText(); System.out.println(name+"\t"+text); } } } 现对该示例解析如下: 查询单个学生的名字,请参见代码第19行 在student.xml中一共有三个学生,在此获取第一个学生的名字 获取student.xml中所有的节点,请参见代码第28行 关于XPATH的更多规则请您参见XPathTutorial JUnit单元测试 为测试方便,可用JUnit进行测试。比如写一个方法,将待测试的代码置于方法体内即可。在使用过程中,请注意: 1、测试方法的返回值为void 2、测试方法无输入参数 3、测试方法需是public的 4、利用Assert测试结果是否正确 示例如下: package cn.com; import junit.framework.Assert; import org.junit.Test; /** * 本文作者:谷哥的小弟 * 博客地址:http://blog.csdn.net/lfdfhl */ public class TestJUnit { @Test public void test1(){ int c=1+2; Assert.assertEquals(3, c); } @Test public void test2(){ int c=1+2; Assert.assertEquals(4, c); } } 最后,贴出项目结构图,如下所示:

资源下载

更多资源
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等操作系统。

用户登录
用户注册