Java笔记

JavaNote

标签(空格分隔): java


sqlserver递归

with subqry(id,name_,oa_task_id) as (
select id,name_,oa_task_id from oa_task where id = '402880eb65f593670165f5c39cea0011'
union all
select oa_task.id,oa_task.name_,oa_task.oa_task_id from oa_task,subqry
where oa_task.oa_task_id = subqry.id
) select * from subqry

IFRAME自适应高度

//IFRAME自适应高度
function setIframeHeight(iframe) {
	if (iframe) {
	var iframeWin = iframe.contentWindow || iframe.contentDocument.parentWindow;
	if (iframeWin.document.body) {
	iframe.height = iframeWin.document.documentElement.scrollHeight || iframeWin.document.body.scrollHeight;
	}
	}
	};

	window.onload = function () {
	setIframeHeight(document.getElementById('external-frame'));
	};

SQLSERVER2008分页查询

SELECT TOP rows 
         * 
FROM     website_news 
WHERE    id NOT IN 
         ( 
		  SELECT TOP ( rows 
				   *( page -1)) id 
FROM     website_news 
ORDER BY systemusertime_ ) 
ORDER BY systemusertime_ ;

下拉框命中

<select name="base_dict_zuBie1_code" id="base_dict_zuBie1_code" class="select_120 easyui-validatebox" ${not empty command.id?"disabled":""}  data-options="required:true" missingMessage="必须选择试验组别!" onchange="setSyzb2(this.value);" >
					<option value="">--请选择--</option>
					<%-- <c:forEach items="${base_syzbs}" var="dict">
						<option value="${dict.code}" ${command.base_dict_zuBie1_code eq dict.code or pref_chanliang.base_dict_zuBie1_code eq dict.code?'selected':'' }>${dict.name}</option>
					</c:forEach> --%>
					 <c:forEach items="${base_syzbs}" var="dict">
						<c:if test="${not empty command.id}">
							<option value="${dict.code}" ${command.base_dict_zuBie1_code eq dict.code?'selected':''}>${dict.name}</option>
						</c:if>
						<c:if test="${empty command.id}">
<%-- 						<c:if test="${empty command.id and not empty pref_xingzhuang}"> --%>
							<option value="${dict.code}" ${pref_xingzhuang.base_dict_zuBie1_code eq dict.code?'selected':''}>${dict.name}</option>
						</c:if>
					</c:forEach> 
				</select>

js转date格式

    new Date(value).format("yyyy-MM-dd");

tomcat之server.xml配置说明,tomcat端口说明

<Server port="8005" shutdown="SHUTDOWN">
<!-- 属性说明
	port:指定一个端口,这个端口负责监听关闭Tomcat的请求
	shutdown:向以上端口发送的关闭服务器的命令字符串
-->
 
  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
 
  <GlobalNamingResources>
 
    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
 
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
       description="User database that can be updated and saved"
           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
          pathname="conf/tomcat-users.xml" />
 
  </GlobalNamingResources>
<!--
    每个Service元素只能有一个Engine元素.元素处理在同一个<Service>中所有<Connector>元素接收到的客户请求
-->
  <Service name="Catalina">
<!-- 属性说明
	name:Service的名称
-->
 
    <!--
		Connector元素:
			由Connector接口定义.<Connector>元素代表与客户程序实际交互的组件,它负责接收客户请求,以及向客户返回响应结果.
    -->
    <Connector port="80" maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               connectionTimeout="20000" disableUploadTimeout="true" />
    <!-- 属性说明
		port:服务器连接器的端口号,该连接器将在指定端口侦听来自客户端的请求。
		enableLookups:如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名;
					若为false则不进行DNS查询,而是返回其ip地址。
		redirectPort:服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号。
		acceptCount:当所有可以使用的处理请求的线程都被用光时,可以放到处理队列中的请求数,超过这个数的请求将不予处理,而返回Connection refused错误。
		connectionTimeout:等待超时的时间数(以毫秒为单位)。
		maxThreads:设定在监听端口的线程的最大数目,这个值也决定了服务器可以同时响应客户请求的最大数目.默认值为200。
		protocol:必须设定为AJP/1.3协议。
		address:如果服务器有两个以上IP地址,该属性可以设定端口监听的IP地址,默认情况下,端口会监听服务器上所有IP地址。
		minProcessors:服务器启动时创建的处理请求的线程数,每个请求由一个线程负责。
		maxProcessors:最多可以创建的处理请求的线程数。
		minSpareThreads:最小备用线程 。
		maxSpareThreads:最大备用线程。
		debug:日志等级。
		disableUploadTimeout:禁用上传超时,主要用于大数据上传时。
    -->
 
 
    <Connector port="8009" 
               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
    <!-- 负责和其他HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时就需要用到这个连接器。 -->
	
    <Engine name="Catalina" defaultHost="localhost">
    <!-- 属性说明
		name:对应$CATALINA_HOME/config/Catalina中的Catalina 
        defaultHost:对应Host元素中的name属性,也就是和$CATALINA_HOME/config/Catalina/localhost中的localhost
		    缺省的处理请求的虚拟主机名,它至少与其中的一个Host元素的name属性值是一样的
        debug:日志等级
    -->
 
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
    <!--
		由Host接口定义.一个Engine元素可以包含多个<Host>元素.
			每个<Host>的元素定义了一个虚拟主机.它包含了一个或多个Web应用.
    -->
    <Host name="localhost" appBase="webapps"
       unpackWARs="true" autoDeploy="true"
       xmlValidation="false" xmlNamespaceAware="false">
	
    <!-- 属性说明
		name:在此例中一直被强调为$CATALINA_HOME/config/Catalina/localhost中的localhost虚拟主机名
		debug:是日志的调试等级 
		appBase:默认的应用路径,也就是把应用放在一个目录下,并在autoDeploy为true的情况下,可自动部署应用此路径相对于$CATALINA_HOME/ (web applications的基本目录)
		unpackWARs:设置为true,在Web应用为*.war是,解压此WAR文件. 
				   如果为true,则tomcat会自动将WAR文件解压;否则不解压,直接从WAR文件中运行应用程序.
		autoDeploy:默认为true,表示如果有新的WEB应用放入appBase 并且Tomcat在运行的情况下,自动载入应用 
    -->
 
	<Context path="/demm" docBase="E:\\projects\\demm\\WebRoot" debug="0" reloadable="true" > 
        </Context>
    <!-- 属性说明
		path:访问的URI,如:http://localhost/是我的应用的根目录,访问此应用将用:http://localhost/demm进行操作,此元素必须,
			表示此web application的URL的前缀,用来匹配一个Context。请求的URL形式为http://localhost:8080/path/*
        docBase:WEB应用的目录,此目录必须符合Java WEB应用的规范,web application的文件存放路径或者是WAR文件存放路径。
        debug:日志等级 
        reloadable:是否在程序有改动时重新载入,设置成true会影响性能,但可自动载入修改后的文件,
			如果为true,则Tomcat将支持热部署,会自动检测web application的/WEB-INF/lib和/WEB-INF/classes目录的变化,
			自动装载新的JSP和Servlet,我们可以在不重起Tomcat的情况下改变web application
    -->
      </Host>
    </Engine>
  </Service>
</Server>


sun.misc.BASE64Encoder找不到jar包的解决方法

1.右键项目-》属性-》java bulid path-》jre System Library-》access rules-》resolution选择accessible,下面填上** 点击确定即可!!!

在MyEclipse中编写Java代码时,用到了BASE64Decoder,import sun.misc.BASE64Decoder;可是Eclipse提示:
Access restriction: The type BASE64Decoder is not accessible due to restriction on required library C:\Program
files\java\jre6\lib\rt.jar
Access restriction : The constructor BASE64Decoder() is not accessible due to restriction on required library C:\Program files\java\jre6\lib\rt.jar

解决方案1(推荐):
只需要在project build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。
解决方案2:
Windows -> Preferences -> Java -> Compiler -> Errors/Warnings ->
Deprecated and trstricted API -> Forbidden reference (access rules): -> change to warning


解决8080端口冲突

netstat -ano | findstr 8080

taskkill -pid 进程pid -f


序列化详谈

子类序列化与父类序列化(Serializable)的区别

  1. 如果子类实现Serializable接口而父类未实现时,父类不会被序列化!
  2. 如果父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。
    原因:

这个就跟子类/父类的内存分配有关系了,具体可看如下博文:
http://blog.csdn.net/smithdoudou88/article/details/12756187
http://blog.csdn.net/u011386422/article/details/42582605


java克隆对象(浅克隆和深克隆)

1.什么是"克隆"?
在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在 Java语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。
Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

2.怎样应用clone方法
一个很典型的调用clone()代码如下:

复制代码

 1 class CloneClass implements Cloneable{ 
 2  public int aInt; 
 3  public Object clone(){ 
 4   CloneClass o = null; 
 5   try{ 
 6    o = (CloneClass)super.clone(); 
 7   }catch(CloneNotSupportedException e){ 
 8    e.printStackTrace(); 
 9   } 
10   return o; 
11  } 
12 }

复制代码
有三个值得注意的地方,一是希望能实现clone功能的CloneClass类实现了Cloneable接口,这个接口属于java.lang 包,java.lang包已经被缺省的导入类中,所以不需要写成java.lang.Cloneable。另一个值得请注意的是重载了clone()方 法。最后在clone()方法中调用了super.clone(),这也意味着无论clone类的继承结构是什么样的,super.clone()直接或 间接调用了java.lang.Object类的clone()方法。下面再详细的解释一下这几点。

应该说第三点是最重要的,仔细 观察一下Object类的clone()一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为 什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。对于第二点,也要 观察Object类中的clone()还是一个protected属性的方法。这也意味着如果要应用clone()方法,必须继承Object类,在 Java中所有的类是缺省继承Object类的,也就不用关心这点了。然后重写clone()方法。还有一点要考虑的是为了让其它类能调用这个clone 类的clone()方法,重写之后要把clone()方法的属性设置为public。

那么clone类为什么还要实现 Cloneable接口呢?稍微注意一下,Cloneable接口是不包含任何方法的!其实这个接口仅仅是一个标志,而且这个标志也仅仅是针对 Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的clone()方法(也就是调用了 super.Clone()方法),那么Object的clone()方法就会抛出CloneNotSupportedException异常。

3.深拷贝与浅拷贝
浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。举例来说更加清楚:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。

若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝,下面我们着重谈一下深拷贝。运行下面的程序,看一看浅拷贝:

复制代码

 1 class Professor0 implements Cloneable {
 2     String name;
 3     int age;
 4  
 5     Professor0(String name, int age) {
 6         this.name = name;
 7         this.age = age;
 8     }
 9  
10     public Object clone() throws CloneNotSupportedException {
11         return super.clone();
12     }
13 }
 1 class Student0 implements Cloneable {
 2     String name;// 常量对象。
 3     int age;
 4     Professor0 p;// 学生1和学生2的引用值都是一样的。
 5  
 6     Student0(String name, int age, Professor0 p) {
 7         this.name = name;
 8         this.age = age;
 9         this.p = p;
10     }
11  
12     public Object clone() {
13         Student0 o = null;
14         try {
15             o = (Student0) super.clone();
16         } catch (CloneNotSupportedException e) {
17             System.out.println(e.toString());
18         }
19  
20         return o;
21     }
22 }

复制代码
复制代码

 1 public class ShallowCopy {
 2     public static void main(String[] args) {
 3         Professor0 p = new Professor0("wangwu", 50);
 4         Student0 s1 = new Student0("zhangsan", 18, p);
 5         Student0 s2 = (Student0) s1.clone();
 6         s2.p.name = "lisi";
 7         s2.p.age = 30;
 8         s2.name = "z";
 9         s2.age = 45;
10         System.out.println("学生s1的姓名:" + s1.name + "\n学生s1教授的姓名:" + s1.p.name + "," + "\n学生s1教授的年纪" + s1.p.age);// 学生1的教授
11     }
12 }

复制代码
运行结果:

s2变了,但s1也变了,证明s1的p和s2的p指向的是同一个对象。这在我们有的实际需求中,却不是这样,因而我们需要深拷贝:

复制代码

 1 class Professor implements Cloneable {
 2     String name;
 3     int age;
 4  
 5     Professor(String name, int age) {
 6         this.name = name;
 7         this.age = age;
 8     }
 9  
10     public Object clone() {
11         Object o = null;
12         try {
13             o = super.clone();
14         } catch (CloneNotSupportedException e) {
15             System.out.println(e.toString());
16         }
17         return o;
18     }
19 }

复制代码
复制代码

 1 class Student implements Cloneable {
 2     String name;
 3     int age;
 4     Professor p;
 5  
 6     Student(String name, int age, Professor p) {
 7         this.name = name;
 8         this.age = age;
 9         this.p = p;
10     }
11  
12     public Object clone() {
13         Student o = null;
14         try {
15             o = (Student) super.clone();
16         } catch (CloneNotSupportedException e) {
17             System.out.println(e.toString());
18         }
19         o.p = (Professor) p.clone();
20         return o;
21     }
22 }

复制代码
复制代码

 1 public class DeepCopy {
 2     public static void main(String args[]) {
 3         long t1 = System.currentTimeMillis();
 4         Professor p = new Professor("wangwu", 50);
 5         Student s1 = new Student("zhangsan", 18, p);
 6         Student s2 = (Student) s1.clone();
 7         s2.p.name = "lisi";
 8         s2.p.age = 30;
 9         System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age);// 学生1的教授不改变。
10         long t2 = System.currentTimeMillis();
11         System.out.println(t2-t1);
12     }
13 }

复制代码
运行结果:

当然我们还有一种深拷贝方法,就是将对象串行化:

复制代码

 1 class Professor2 implements Serializable {
 2     /**
 3      * 
 4      */
 5     private static final long serialVersionUID = 1L;
 6     String name;
 7     int age;
 8  
 9     Professor2(String name, int age) {
10         this.name = name;
11         this.age = age;
12     }

复制代码
复制代码

 1 class Student2 implements Serializable {
 2     /**
 3      * 
 4      */
 5     private static final long serialVersionUID = 1L;
 6     String name;// 常量对象。
 7     int age;
 8     Professor2 p;// 学生1和学生2的引用值都是一样的。
 9  
10     Student2(String name, int age, Professor2 p) {
11         this.name = name;
12         this.age = age;
13         this.p = p;
14     }
15  
16     public Object deepClone() throws IOException, OptionalDataException,
17             ClassNotFoundException {
18         // 将对象写到流里
19         ByteArrayOutputStream bo = new ByteArrayOutputStream();
20         ObjectOutputStream oo = new ObjectOutputStream(bo);
21         oo.writeObject(this);
22         // 从流里读出来
23         ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
24         ObjectInputStream oi = new ObjectInputStream(bi);
25         return (oi.readObject());
26     }
27  
28 }

复制代码
复制代码

 1 public class DeepCopy2 {
 2      
 3     /**
 4      * @param args
 5      */
 6     public static void main(String[] args) throws OptionalDataException,
 7             IOException, ClassNotFoundException {
 8         long t1 = System.currentTimeMillis();
 9         Professor2 p = new Professor2("wangwu", 50);
10         Student2 s1 = new Student2("zhangsan", 18, p);
11         Student2 s2 = (Student2) s1.deepClone();
12         s2.p.name = "lisi";
13         s2.p.age = 30;
14         System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // 学生1的教授不改变。
15         long t2 = System.currentTimeMillis();
16         System.out.println(t2-t1);
17     }
18  
19 }

复制代码
要想序列化对象,必须先创建一个OutputStream,然后把它嵌入ObjectOutputStream。这时就能用writeObject()方法把对象写入OutputStream。读的时候需要把InputStream嵌到ObjectInputStream中,然后再调用readObject()方法。不过这样读出来的只是一个Object的reference,因此,在用之前,还要下转型。

对象序列化不仅能保存对象的副本,而且会跟着对象中的reference把它所引用的对象也保存起来,然后再继续跟踪那些对象的reference,以此类推。这种情形常被称作”单个对象所联结的‘对象网’ “。

但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。

本篇文章来源于两位前辈的博文,以及《java程序员面试宝典》。为了表示对他人劳动成果的尊重,这里标注出处:

http://www.cnblogs.com/shuaiwhu/archive/2010/12/14/2065088.html
http://www.cnblogs.com/o-andy-o/archive/2012/04/06/2434904.html


eclipse 重新生成class文件

class文件删除之后,eclipse上方菜单条project点击清除,然后重新启动项目就可以了


c标签<c:choose>


<c:choose>
					<c:when test="${file.ext eq 'docx' || file.ext eq 'doc'}">   
						<img id="img(${sta.index})"  src="${ctx}/icons/icon_doc.jpg" onerror="src='${ctx}/images/card/touming.png'" class="image_add" objId="${file.id}"/>     
					</c:when>
					<c:when test="${file.ext eq 'xlsx' || file.ext eq 'xls'}">   
						<img id="img(${sta.index})"  src="${ctx}/icons/icon_xlsx.jpg" onerror="src='${ctx}/images/card/touming.png'" class="image_add" objId="${file.id}"/>   
					</c:when>
					<c:otherwise> 
						<img id="img(${sta.index})"  src="${ctx}/icons/icon_file.jpg" onerror="src='${ctx}/images/card/touming.png'" class="image_add" objId="${file.id}"/>
					</c:otherwise>
				</c:choose>


el表达式数字循环

<c:forEach var="i" begin="1" end="${totalPage}">

jstl获取当前时间

在JSP页首引用:

<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<jsp:useBean id="now" class="java.util.Date" scope="page"/>
<fmt:formatDate var="nowyear" value='${now}'  pattern='yyyy'/>


<%@ include file=""%>与<jsp:include page=""/>两种方式的作用


EL表达式对字符串处理

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

下面是JSTL中自带的方法列表以及其描述

函数名 函数说明 使用举例

fn:contains 判定字符串是否包含另外一个字符串

<c:if test="${fn:contains(name, searchString)}"> 

fn:containsIgnoreCase 判定字符串是否包含另外一个字符串(大小写无关)

    <c:if test="${fn:containsIgnoreCase(name, searchString)}"> 

fn:endsWith 判定字符串是否以另外字符串结束

<c:if test="${fn:endsWith(filename, ".txt")}"> 

fn:escapeXml 把一些字符转成XML表示,例如

<字符应该转为&lt; ${fn:escapeXml(param:info)} 

fn:indexOf 子字符串在母字符串中出现的位置 
${fn:indexOf(name, "-")} 

fn:join 将数组中的数据联合成一个新字符串,并使用指定字符格开

${fn:join(array, ";")} 

fn:length 获取字符串的长度,或者数组的大小

${fn:length(shoppingCart.products)} 

fn:replace 替换字符串中指定的字符

${fn:replace(text, "-", "&#149;")} 

fn:split 把字符串按照指定字符切分

${fn:split(customerNames, ";")} 

fn:startsWith 判定字符串是否以某个子串开始

<c:if test="${fn:startsWith(product.id, "100-")}"> 

fn:substring 获取子串

${fn:substring(zip, 6, -1)} 

fn:substringAfter 获取从某个字符所在位置开始的子串

${fn:substringAfter(zip, "-")} 

fn:substringBefore 获取从开始到某个字符所在位置的子串

${fn:substringBefore(zip, "-")} 

fn:toLowerCase 转为小写

${fn.toLowerCase(product.name)} 

fn:toUpperCase 转为大写字符

${fn.UpperCase(product.name)} 

fn:trim 去除字符串前后的空格

${fn.trim(name)} 

String 转date

new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(String)


如何生成比较像样的假数据


jsp下读取c:forEach的循环次数,以及内部循环数据累加统计等

前言
近日接触到一个比较旧的项目,框架使用的是Status2+Spring3,前端jsp大量内嵌了java代码,几乎未使用jstl和el表达式。
个人习惯原因,已经很不喜欢使用这种通过写java代码在jsp上做逻辑控制的方式,很不好让别人读代码。

表达式循环有几种方式,这里只说c:forEach。
在网上看了一下,没有自己需要的,自己写一个。
场景需求:
某用户登录后查看自己的购物车,及时显示其购物车内的商品种类和合计金额。

原理:
自己创建jstl变量,存储自己需要统计的内容放到循环体里执行即可。
定义2个变量,row_total统计金额,row_count统计数量

<c:set var="row_total" value="0"></c:set>
<c:set var="row_count" value="0"></c:set>

之后自己在循环体里进行运算,这个是自加1

<c:set var="row_count" value="${row_count+1}" />

这个是进行运算

<c:set var="row_total" value="${row_total +(productprice*rowData.productnum) }" />

之后在循环体外直接使用表达式,就是你需要的统计数据了

${row_total }   
${row_count }

然后备注一下,jsp页面头请引入jstl标签库

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

补充1
上面的例子上使用到了下面的标签,作用是格式化数字的

fmt:parseNumber

头部需引入

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 

补充2
在c:foreach里同样也有统计字段,可以使用该字段进行统计,但只能在循环体内,完整用法如下,使用$
可以获取循环次数,不过需要注意一下,它的计数是从1开始,而不是0

<c:forEach var=”data" items=”list" varStatus=”status”>
    <c:out value=”${status.current}”/> 当前对象
    <c:out value=”${status.index}”/> 此次迭代的索引
    <c:out value=”${status.count}”/> 已经迭代的数量
    <c:out value=”${status.first}”/> 是否是第一个迭代对象
    <c:out value=”${status.last}”/> 是否是最后一个迭代对象
</c:forEach>

下面是完整例子,用于实现购物车商品的展现与统计

<c:set var="row_total" value="0"></c:set>
<c:set var="row_count" value="0"></c:set>
<c:forEach var="rowData" items="${shopping_data}">
    <fmt:parseNumber var="productprice" value="${rowData.productprice}" type="number" />
    <c:set var="row_total" value="${row_total + (productprice*rowData.productnum) }" />
    <c:set var="row_count" value="${row_count+1}" />
<li>                
    <div class="p-img fl">
        <a href="${path }/productDetail?productId=${rowData.productid }">
        <img src="${path }${rowData.f_productimg}" width="50" height="50" alt=""></a>
    </div>                
    <div class="p-name fl">
        <span></span>
        <a href="${path }/productDetail?productId=${rowData.productid }" title="${rowData.productname}">
            ${rowData.productname}
        </a>
    </div> 
</li>
</c:forEach>

例子:

<c:set var="i" value="1"></c:set>
<c:forEach items="${trace_file_fieldExtends }" var="it" >
	<td class="tdLabel" >${it.name }${i }</td>
    <td class="tdContent"" colspan="${it.cols eq '1' ?3:'' }">
    	<c:if test="${it.type eq 'TIME' }">
    	<input type="text" name="${it.code }" id="${it.code }" value="<fmt:formatDate value="${command.date}" pattern="yyyy-MM-dd"/>" onclick="WdatePicker()"  class="textm validNotNull" msg = "时间不能为空">
    	</c:if>
    	<c:if test="${!(it.type eq 'TIME') }">
    	<input type="text" name="${it.code }" value="" id="${it.code }" class="${it.isnull eq '0'?'validNotNull':''} ${checktype}" />
    	</c:if>
    </td>
	<c:if test="${(sta.index+1)%2 eq 0 }">
	</tr>
	<tr>
	</c:if>
<c:set var="i" value="${i+1}" />
</c:forEach>


@RestController注解

@RestController注解,相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面


@SpringBootApplication

SpringBootApplication:标注这是一个主程序类,说明这是一个springboot的应用程序


SpringApplication.run使spring启动起来

    public static void main(String[] args) {
        /**
         * SpringApplication.run使spring启动起来
         */
        SpringApplication.run(HelloWorldMainApplication.class,args);
    }    

如果一个请求进来,你要在页面上显示字符串,那就必须用print.out,或者@responseBody,否则页面是会报错的


简化部署

在使用maven进行package打包之后,可以把生成的jar进行单独部署
在cmd界面直接运行

java -jar [包名]

即使是没有tomcat也没有关系的,因为springboot自带一个tomcat

启动器
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

spring-boot-starter-web:可以看作场景启动器,帮助我们导入web模块正常运行所依赖的组件

springBoot将所有的功能场景都抽取出来,做成一个歌的Starters(启动器),只需要在项目中引入这些starters相关的场景,所有依赖都会导入


在springboot启动类中,@SpringBootApplication注解的源码中是包含的注解如下

@SpringBootApplication
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration:springboot的配置类,标注在某个类上,说明此类是springboot的配置类
    @EnableAutoConfiguration:开启自动配置的功能,以前需要配置的东西,用EnabledAutoConfiguration此注解帮我们自动配置,只用配置此注解自动配置的功能才能生效
        @Target({ElementType.TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @Inherited
        @AutoConfigurationPackage:自动配置包,将主配置类(@SpringBootApplication标注的类)所在包及子包里面所有的组件扫描到spring容器中
        @Import({EnableAutoConfigurationImportSelector.class}):spring的底层注解,给容器中导入组件,由***.class指定。EnableAutoConfigurationImportSelector:导入组件的选择器,将需要的组件以全类名的方式返回,这些组件就会被添加到容器中,会给容器导入自动配置类,有了自动配置类,免去我们手动编写配置注入功能等工作
        SpringBoot启动的时候会在类路径下的META-INFO获取指定的EnableAutoConfigurationImport值,将这些值作为自动配置导入到容器中,自动配置就会生效。 
        JavaEE整体整合的解决方案和自动配置都在spring-boot-autoconfigure.jar
        
        

@RestController注解就包含了@Controller和@ResponseBody


maven打jar包,配置文件没有被打入

今天在给common项目打包的过程中,发现打出的包中(jar文件)不包含.properties文件,我们项目在读取一些配置时,把信息写在了weifutong.properties 文件中,地址为:XXX_common/src/main/java/com/jf/app/pay/wift/resources/weifutong.properties

原因:maven在打包(jar)时默认只编译和打包java文件

解决方法:在XXX_common项目中的pom中间中添加以下代码:

<build>  
    <!--配置打包时不过滤非java文件开始  -->  
    <!--说明,在进行模块化开发打jar包时,maven会将非java文件过滤掉,  
    xml,properties配置文件等,但是这些文件又是必需的,  
    使用此配置可以在打包时将不会过滤这些必需的配置文件。  
    -->  
    <resources>  
        <resource> 
<!--路径 -->  
            <directory>src/main/java</directory>  
            <includes>  
                <include>**/*.properties</include> 
                <include>**/*.xml</include>  
            </includes>  
            <filtering>false</filtering>  
        </resource>  
        <resource>  
    <!--路径(如果只解决上边的问题,此处配置不需要) -->  
            <directory>src/main/resources</directory>  
            <includes>  
                <include>**/*.properties</include> 
                <include>**/*.xml</include>
                <include>**/*.yml</include>
            </includes>  
            <filtering>false</filtering>  
        </resource>  
    </resources>  
    <!--配置打包时不过滤非java文件结束 -->  
</build> 

关于java中BufferedReader的read()及readLine()方法的使用心得


Missing artifact com.google.code.kaptcha:kaptcha:jar:2.3

在学习<Maven实战>时,按照书中的一个事例练习,其中需要依赖一个jar包,叫kaptcha-2.3-jdk15.jar,这个jar包是用来生成验证码的开源类库,由于没有上传到中央仓库,因此需要在项目中声明这个发布该类库的仓库地址

    <dependencies>
        <!--google的验证码框架-->
        <dependency>
            <groupId>com.google.code.kaptcha</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3</version>
        </dependency>
    </dependencies>

<!--添加另一个maven仓库的分支,因为kaptcha框架在这个仓库里面,尴尬-->
    <repositories>
        <repository>
            <id>Jahia</id>
            <name>Jahia Repository</name>
            <url>http://maven.jahia.org/maven2/</url>
            <layout>default</layout>
        </repository>
    </repositories>


shiro

辣鸡!!!!!!!!!!!!!!!!!!!!!!!!

shiro是监听loginUrl的请求,它会看你loginUrl页面上的form中的username,password,rememberMe的值然后登陆,而这个form是不用指定登陆的action的。
所以struts2的loginAction实际上是跟shiro无关的,你重写FormAuthenticationFilter的onLoginSu
ccess方法即可。


shiro的验证码刷新

前端直接调用就ok

//刷新验证码
	function refreshCaptcha(){
		$("#captcha_img").attr("src","/kaptcha.jpg");
	}

mybatis的插入返回id

这样就可以,要注意的是,返回的对象才有id自动绑定上去,注意有没有
BeanUtils.copyProperties(personVo, person);
的情况

<insert id="insert" parameterType="com.genye.sorter.power.pojo.po.Person" useGeneratedKeys="true" keyProperty="id">
</insert>

springMVC的controller单例和多例下成员变量的问题

单例模式下会共享普通成员变量和静态成员变量,多例模式下普通成员变量不共享,静态成员共享.
在开发中,springMVC优先使用单例模式,而且尽量不要在controller中设定成员变量.
如果要定义成员变量并为成员变量赋值可以配置source.properties,通过读取配置文件为成员变量初始化.

单例模式下会共享普通成员变量和静态成员变量,多例模式下普通成员变量不共享,静态成员共享.
在开发中,springMVC优先使用单例模式,而且尽量不要在controller中设定成员变量.
如果要定义成员变量并为成员变量赋值可以配置source.properties,通过读取配置文件为成员变量初始化.


匿名map

new HashMap<String,Object>(){{put("a", "1");}}

明文md5加盐

说的就是把salt加在明文的某个位置然后再进行md5加密
突然感觉好low
shiro中的md5加盐是把


shiro中在Realm中的

/**
     * 认证信息.(身份验证)
     * Authentication 是用来验证用户身份
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {

        //System.out.println("MyShiroRealm.doGetAuthenticationInfo()");

        //获取用户的输入的账号.
        String username = (String)token.getPrincipal();
        //System.out.println("用户的账号:"+username);

        //通过username从数据库中查找 ManagerInfo对象
        //实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法
        ManagerInfo managerInfo = managerInfoService.findByUsername(username);

//        System.out.println("----->>managerInfo="+managerInfo.toString());
        if(managerInfo == null){
            return null;
        }

        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                managerInfo, //#############这里存放登录成功的对象或者用户名###############
                managerInfo.getPassword(), //密码
                ByteSource.Util.bytes(managerInfo.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );

        //明文: 若存在,将此用户存放到登录认证info中,无需自己做密码对比,Shiro会为我们进行密码对比校验
//        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
//                managerInfo, //用户名
//                managerInfo.getPassword(), //密码
//                getName()  //realm name
//        );
        return authenticationInfo;
    }

java lamda表达式

比如说:

线程


几个比较新奇的类

nametypedescription
ConsumerConsumer< T >接收T对象,不返回值
PredicatePredicate< T >接收T对象并返回boolean
FunctionFunction< T, R >接收T对象,返回R对象
SupplierSupplier< T >提供T对象(例如工厂),不接收值
UnaryOperatorUnaryOperator接收T对象,返回T对象
BinaryOperatorBinaryOperator接收两个T对象,返回T对象

Consumer 输入

public static void main(String args[]){
    Teacher tt = new Teacher();
    tt.setName("teacher");
    Consumer<Teacher> consumer1 = t -> System.out.println("先执行我");
    Consumer<Teacher> consumer2 = t -> System.out.println("然后执行我");
    consumer1.andThen(consumer1).andThen(consumer2).accept(tt);
}

Supplier 输出

public static void main(String[] args) {
	Supplier<Teacher> supplier = () -> {
		Teacher taTeacher = new Teacher();
		taTeacher.setName("aaa");
		return taTeacher;
	};
	Teacher t = supplier.get();
	System.out.println(t.getName());
}

Supplier<Teacher> taSupplier = Teacher::new;//饿汉式单例

利用集合运算提高程序的效率以及代码简洁度。

做项目开发时会经常遇到这样的情况,从用户表得到了一批用户id集合,根据业务需求需要过滤掉一些不符合业务需求的用户id,将余下的用户id在进行别的也操作。那么,经常看到有同事是通过如下代码来处理的:

List<Long> uidList = new ArrayList<>();
uidList.add(2122346211L);
uidList.add(2126554121L);
uidList.add(2126562651L);
uidList.add(2265621171L);
uidList.add(4126216721L);

List<Long> removeList = new ArrayList<>();
removeList .add(2265621171L);
removeList .add(4126216721L);

uidList.removeAll(removeList);

还有一种方法是通过iterator去移除集合内的对象。基础好点的都知道,在对原集合边遍历边移除是会抛异常的,要想边遍历边移除只能用迭代器(iterator)才能够实现。而我推荐的做法是对两集合求差集,而不是调用集合的removeAll()方法,具体代码如下:

// 集合差集
List resultList = (ArrayList) CollectionUtils.subtract(listA, listB);

// 集合并集
List resultList = (ArrayList) CollectionUtils.union(listA, listB);

// 集合交集
List resultList = (ArrayList) CollectionUtils.intersection(listA, listB);

可能有人会疑惑,将Collection强制转化为list会不会抛异常,其实不必担心,看看源码(源码如下)就是知道,CollectionUtils在做差集时将结果集保存到了ArrayList 中,所以不会出现强制转化异常。

public static Collection subtract(Collection a, Collection b) {
        ArrayList list = new ArrayList(a);
        Iterator it = b.iterator();

        while(it.hasNext()) {
            list.remove(it.next());
        }

        return list;
   }

细心的人会发现,CollectionUtils.subtract()方法就是采用迭代器移除的方法实现的,那么你还有什么理由自己去写一遍这样的代码呢?


Java Socket定长通讯读取消息长度头

数据在网络传输时使用的都是字节流,Socket也不例外,所以我们发送数据的时候需要转换为字节发送,读取的时候也是以字节为单位读取。
那么问题就在于socket通讯时,接收方并不知道此次数据有多长,因此无法精确地创建一个缓冲区(字节数组)用来接收,在不定长通讯中,通常使用的方式时每次默认读取8*1024长度的字节,若输入流中仍有数据,则再次读取,一直到输入流没有数据为止。但是如果发送数据过大时,发送方会对数据进行分包发送,这种情况下或导致接收方判断错误,误以为数据传输完成,因而接收不全。
所以,大部分情况下,双方使用socket通讯时都会约定一个定长头放在传输数据的最前端,用以标识数据体的长度,通常定长头有整型int,短整型short,字符串Strinng三种形式。


aop after-returning 和after的区别?

try{
    try{
        //@Before
        method.invoke(..);
    }finally{
        //@After
    }
    //@AfterReturning
}catch(){
    //@AfterThrowing
}


线程池一定要一定要使用静态static修饰!!!


BeanUtils.copyProperties在拷贝属性时忽略空值

public static String[] getNullPropertyNames (Object source) {
    final BeanWrapper src = new BeanWrapperImpl(source);
    java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

    Set<String> emptyNames = new HashSet<String>();
    for(java.beans.PropertyDescriptor pd : pds) {
        Object srcValue = src.getPropertyValue(pd.getName());
        if (srcValue == null) emptyNames.add(pd.getName());
    }
    String[] result = new String[emptyNames.size()];
    return emptyNames.toArray(result);
}

public static void copyPropertiesIgnoreNull(Object src, Object target){
    org.springframework.beans.BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
}

Ant 风格路径表达式

ANT通配符有三种:
|通配符|说明|
|-|-|
|?|匹配任何单字符|
|*|匹配0或者任意数量的字符|
|**|匹配0或者更多的目录|

例子

URL路径说明
/app/*.x匹配(Matches)所有在app路径下的.x文件
/app/p?ttern匹配(Matches) /app/pattern 和 /app/pXttern,但是不包括/app/pttern
/**/example匹配(Matches) /app/example, /app/foo/example, 和 /example
/app/**/dir/file.*匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java
/**/*.jsp匹配(Matches)任何的.jsp 文件

属性:
最长匹配原则(has more characters)
说明,URL请求/app/dir/file.jsp,现在存在两个路径匹配模式/**/.jsp和/app/dir/.jsp,那么会根据模式/app/dir/*.jsp来匹配


PrintWriter 输出信息乱码

异步方式,返回json给前台时,向前台输出信息使用PrintWriter,但是在输出的过程中,出现乱码的情况。

于是我想起来response.setCharacterEncoding("utf-8");设置页面编码,以及response.setContentType("text/html; charset=utf-8");设置内容类型编码,但是在实验后不成功,乱码依旧。

PrintWriter out = response.getWriter();
response.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
out.print(json);
out.flush();
out.close();

返回的json如下:

 {"seriesData":[22619,22671,21908,5415,0],"caption":"组织机构代码-年度统计","xAxisData":["2010年度","2011年度","2012年度","2013年度","2014年度"]}

经检查,发现PrintWriter会先获取项目的 编码,根据编码来自己设定characterEncoding,所以得在获取这个PrintWriter对象之前设置编码。如下:注意顺序。

顺序很重要!!!

    response.setCharacterEncoding("utf-8");
    response.setContentType("text/html; charset=utf-8");
    PrintWriter out = response.getWriter();
    out.print(json);
    out.flush();
    out.close();

mybatis循环

<select id="listByTypes" parameterType="list" resultMap="BaseResultMap">
	select
    <include refid="com.genye.sorter.base.dao.EntranceMapper.Base_Column_List" />
    from sorter_base_entrance
    WHERE type IN 
    <foreach item="item" collection="array" separator="," open="(" close=")" index="">  
  		#{item, jdbcType=NUMERIC}  
	</foreach>  
</select>

easyui 模糊查询

参考博客
前端:

<input id="originDest" name="originId" th:class="easyui-combobox"
                         data-options="
		                    label:'品种名称:',
		                   required:true,
		                   labelAlign:'right',
		                   labelWidth:'150',
		                   valueField: 'id',
		                   textField: 'text',
		                   editable:true,
		                   mode:'remote',
		                   url: ctx + 'desBusinessAction/destinationData'
		                "
                    /> 

后台

/**
	 * 获取所有的destination数据
	 * @param destId
	 * @param q  easyui模糊查询时输入的参数,默认为q
	 * @return
	 */
	@RequestMapping("/destinajtionData")
	@ResponseBody
	public List<Combobox> destinationData(String destId,String q) {
		List<Combobox> comboboxs = new ArrayList<Combobox>();
		List<Destination> all = destinationService.getAll();
		if(all!=null&&all.size()>0) {
			for (Destination destination : all) {
				if(StringUtil.isNotEmpty(destId)
						&&destination.getId().toString().equals(destId)) {
					continue;
				}
				if(StringUtil.isNotEmpty(q)
				        &&destination.getName().toString().indexOf(q)==-1) {
				    continue;
				}
				comboboxs.add(new Combobox(destination.getId()+"",destination.getName()));
			}
		}
		return comboboxs;
	}

TCP粘包和拆包

TCP是基于字节流的传输协议。那么数据在通信层传播其实就像河水一样并没有明显的分界线,而数据具体表示什么意思什么地方有句号什么地方有分号这个对于TCP底层来说并不清楚。应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段,之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。所以对于这个数据拆分成大包小包的问题就是我们今天要讲的粘包和拆包的问题。


线程使用的lambda表达式

new Thread(()->{
    //语句

    }).start();

netty

IO 读写是面向流的,一次性只能从流中读取一个或者多个字节,并且读完之后流无法再读取,你需要自己缓存数据。 而 NIO 的读写是面向 Buffer 的,你可以随意读取里面任何一个字节数据,不需要你自己缓存数据,这一切只需要移动读写指针即可。

  1. NIO 模型中通常会有两个线程,每个线程绑定一个轮询器 selector ,在我们这个例子中serverSelector负责轮询是否有新的连接,clientSelector负责轮询连接是否有数据可读
  2. 服务端监测到新的连接之后,不再创建一个新的线程,而是直接将新连接绑定到clientSelector上,这样就不用 IO 模型中 1w 个 while 循环在死等,参见(1)
  3. clientSelector被一个 while 死循环包裹着,如果在某一时刻有多条连接有数据可读,那么通过 clientSelector.select(1)方法可以轮询出来,进而批量处理,参见(2)
  4. 数据的读写面向 Buffer,参见(3)

同一服务器下部署两个相同shiro项目(端口不同)导致账号登录失败处理

1、情况
在同一个服务器下部署两套相同的shiro项目,端口号不同
2、出现问题:
两个系统同时登陆后会出现相互干扰的情况
3、原因:
同一个域名下两个系统的cookie名称相同(shiro默认的cookie名为;JSESSIONID),相互覆盖;
4、解决方案
实现自定义类继承DefaultWebSessionManager

package com.genye.sorter.power.shiroconfig;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
 
public class AngWebSessionManager extends DefaultWebSessionManager {
    /**
     * 重写onStart方法,该方法在生成session时可调用
     * 此时可对父类SessionIdCookie进行操作,更改其CookiseName的值
     * 默认为JSESSIONID,可由配置注入单个统一名称
     * 重写方法可实现多个名称,运用于在同一服务器上部署两个相同项目导致的登录干扰
     * 使用方法替换注入DefaultWebSessionManager
     */
    @Override
    protected void onStart(Session session, SessionContext context) {
        /**
         * JSESSIONID改为JSESSIONID+当前毫秒数,如果后续出现同一服务器
                  * 部署两个不同项目,都采用shiro,建议更改为JSESSIONID+项目名缩写
         */
        super.getSessionIdCookie().setName("JSESSIONID"+System.currentTimeMillis());
        super.onStart(session, context);
    }
}

在shiroconfig中进行配置

    /**
     * securityManager
     * @return
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm
        securityManager.setRealm(powerShiroRealm());
        //注入自定义sessionManager
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }


    /**
          * 注入自定义sessionManager
     * @return
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        AngWebSessionManager angWebSessionManager = new AngWebSessionManager();
        //删除失效的session
        angWebSessionManager.setDeleteInvalidSessions(true);
        return angWebSessionManager;
    }

完成!


# Java  笔记 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×