WdatePicker日历控件使用方法

1. 跨无限级框架显示

 

无论你把日期控件放在哪里,你都不需要担心会被外层的iframe所遮挡进而影响客户体验,因为My97日期控件是可以跨无限级框架显示的

 

示例2-7 跨无限级框架演示

可无限跨越框架iframe,无论怎么嵌套框架都不必担心了,即使有滚动条也不怕

 

2. 民国年日历和其他特殊日历

 

当年份格式设置为yyy格式时,利用年份差量属性yearOffset(默认值1911民国元年),可实现民国年日历和其他特殊日历

示例2-8 民国年演示

注意:年份格式设置成yyy时,真正的日期将会减去一个差量yearOffset(默认值为:1911),如果是民国年使用默认值即可无需另外配置,如果是其他的差量,可以通过参数的形式配置

 

3. 为编程带来方便

如果el的值是this,可省略,即所有的el:this都可以不写 
日期框设置为disabled时,禁止更改日期(不弹出选择框) 
如果没有定义onpicked事件,自动触发文本框的onchange事件 
如果没有定义oncleared事件,清空时,自动触发onchange事件

 

4. 其他属性

设置readOnly属性,可指定日期框是否只读 
设置highLineWeekDay属性,可指定是否高亮周末 
设置isShowOthers属性,可指定是否显示其他月的日期 
加上class=”Wdate”就会在选择框右边出现日期图标

 

 

多语言和自定义皮肤

1. 多语言支持

通过lang属性,可以为每个日期控件单独配置语言,当然也可以通过WdatePicker.js配置全局的语言
语言列表和语言安装说明详见语言配置

示例3-1 多语言示例

繁体中文: 

英文: 

简体中文: 

注意:默认情况lang=’auto’,即根据浏览器的语言自动选择语言.

 

2. 自定义和动态切换皮肤

通过skin属性,可以为每个日期控件单独配置皮肤,当然也可以通过WdatePicker.js配置全局的皮肤
皮肤列表和皮肤安装说明详见皮肤配置

 

示例3-2 皮肤演示

默认皮肤default: skin:’default’

注意:在WdatePicker里配置了skin=’default’,所以此处可省略,同理,如果你把WdatePicker里的skin配置成’whyGreen’那么在不指定皮肤的情况下都使用’whyGreen’皮肤了

 

       whyGreen皮肤: skin:’whyGreen’

 

 

4. 日期范围限制

1. 静态限制
注意:日期格式必须与 realDateFmt 和 realTimeFmt 一致

你可以给通过配置minDate(最小日期),maxDate(最大日期)为静态日期值,来限定日期的范围

示例4-1-1 限制日期的范围是 2006-09-10到2008-12-20

 

示例4-1-2 限制日期的范围是 2008-3-8 11:30:00 到 2008-3-10 20:59:30

 

示例4-1-3 限制日期的范围是 2008年2月 到 2008年10月

 

示例4-1-4 限制日期的范围是 8:00:00 到 11:30:00

 

2. 动态限制
注意:日期格式必须与 realDateFmt 和 realTimeFmt 一致

你可以通过系统给出的动态变量,如%y(当前年),%M(当前月)等来限度日期范围,你

还可以通过#{}进行表达式运算,如:#{%d+1}:表示明天

动态变量表

格式

说明

%y

当前年

%M

当前月

%d

当前日

%ld

本月最后一天

%H

当前时

%m

当前分

%s

当前秒

#{}

运算表达式,如:#{%d+1}:表示明天

#F{}

{}之间是函数可写自定义JS代码

 

示例4-2-1 只能选择今天以前的日期(包括今天)

 

示例4-2-2 使用了运算表达式只能选择今天以后的日期(不包括今天)

 

示例4-2-3 只能选择本月的日期1号至本月最后一天

 

示例4-2-4 只能选择今天7:00:00至明天21:00:00的日期

 

      示例4-2-5 使用了运算表达式只能选择 20小时前至 30小时后的日


 

3 . 脚本自定义限制
       注意:日期格式必须与 realDateFmt 和 realTimeFmt 一致

 

系统提供了$dp.$D和$dp.$DV这两个API来辅助你进行日期运算,此外你还可以通过在 #F{} 中填入你自定义的脚本,做任何你想做的日期限制

 

示例4-3-1 前面的日期不能大于后面的日期且两个日期都不能大于 2020-10-01

合同有效期从  到 

注意:
两个日期的日期格式必须相同

$dp.$ 相当于 document.getElementById 函数.
那么为什么里面的 ‘ 使用 \’ 呢? 那是因为 ” 和 ‘ 都被外围的函数使用了,故使用转义符 \ ,否则会提示JS语法错误.
所以您在其他地方使用时注意把 \’ 改成 ” 或者 ‘ 来使用.

#F{$dp.$D(\’d4312\’)||\’2020-10-01\’} 表示当 d4312 为空时, 采用 2020-10-01 的值作为最大值

 

示例4-3-2 前面的日期+3天 不能大于 后面的日期

       日期从  到 
      

       onFocus=”WdatePicker({maxDate:’#F{$dp.$D(\’d4322\’,{d:-3});}’})”/>
      

       onFocus=”WdatePicker({minDate:’#F{$dp.$D(\’d4321\’,{d:3});}’})”/>

       使用 $dp.$D 函数 可以将日期框中的值,加上定义的日期差量:
       两个参数: id={字符类型}需要处理的文本框的id值 , obj={对象类型}日期差量
  

       日期差量用法:

       属性y,M,d,H,m,s分别代表年月日时分秒

为了使用方便,转过来了。

转至:http://www.xuebuyuan.com/1021922.html

和大彪一起来学习-SpringMvc之第三回(注解使用详解)

简述:

在上一篇文章中,介绍了适配器和映射器的一些概念,这篇文章主要是介绍SpringMvc注解的使用,下面先从一个最简单注解程序开始,慢慢引入一些常用的注解(@Controller,@Component,@Service,@Repository,@RequestMapping,@InitBinder,

@RequestParam,@PathVariable,@RequestBody ,@ResponseBody)

一、第一个注解项目

1.创建项目,加入Jar包,编写web.xml

可以加入第一篇文章里面给出的那些jar包,项目结构如下:
web.xml编写如下,前面已经有介绍过了,这里直接贴图了。

2.编写springmvc-servlet.xml加入注解支持



		
		
		
		 
		
		
	
		
		
		
		
		 
			
		
			
			
		

3.编写Controller类

package com.billstudy.springmvc.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * SpringMvc/Spring 企业开发常用注解使用演示
 * @author Bill
 * @since V1.0 2015/01/23
 */

/** 标明为Controller类,可以被Spring 扫描到,一般此类注解都作用于类上 ,与此相似的还有:
 *  @Service : 一般用于MVC设计中M(model)层,也就是业务层
 *  @Repository : 一般用于DAO层,也就是数据访问层
 *  @Component : 仅仅表示一个组件 (Bean),比较泛化,当我们写了一个类不好定位其在MVC那层的时候,可以使用这个
 *  @Controller:一般用于MVC设计中C(Controller)层,也就是控制层
 * **/
@Controller	
public class AnnotationDemoController{
	
	@RequestMapping("/annotationTest01")/** 定义访问规则 **/
	public ModelAndView annotationTest01(HttpServletRequest request,HttpServletResponse response){
		ModelAndView result = new ModelAndView();
		result.setViewName("/annotationTest01");	// 这里的ViewName,我们把它看成逻辑视图名,最终结合视图解析器,路径为:/WEB-INF/jsp/annotationTest01.jsp
		result.addObject("msg", "注解使用成功了!"); 
		return result;
	}
}

4.部署,测试

二、注解应用

1.@RequestMapping

使用方法1(路径映射):

【URL】加在Controller具体方法上,称为子路径映射。如:@RequestMapping(“/annotationTest01”),这个时候若没有在类上用这个注解,那么可以直接通过【项目名/annotationTest01】访问这个方法了。若是类上面写了@RequestMapping(“/parent“),那么这时候访问就是【项目名/parent/annotationTest01】了,也就是说类中所有的方法,都应该带上/parent,类上面我们称其为根路径映射。
演示:
子路径:
jsp/result.jsp内容:
访问效果:

根路径:类上面写了,那么访问具体方法时,都要带上根路径。
访问测试:

使用方法2(URI
模板模式映射):

@RequestMapping(value=”/parent/{id}”):{×××}占位符,
请求的URL可以是“/
parent/001”或“/parent/abc”,通过在方法中使用@PathVariable获取{×××}中的×××变量。若是有多个,则直接@RequestMapping(value=”/parent/{id}/{name}/{age}“)就可以了
演示:

使用方法3(请求方式限定):

也就是规定客户端请求的类型,如get/post,不按照要求来报 http
405错误
下面使用Firefox的HttpRequest测试,我就不写form/表单测试了,效果都一样。
如果想让方法同时支持get/post,那么可以这么写:@RequestMapping(value=”/postMethod”,method={RequestMethod.POST,RequestMethod.GET}),就是写多个就可以了。
下面的注解解决了一些请求参数绑定,所以例子和请求参数一起测试。

三、注解配合请求实现参数绑定

默认支持(Java基本数据类型,HttpServletRequest 通过request对象获取请求信息
HttpServletResponse 通过response处理响应信息 HttpSession 通过session对象得到session中存放的对象 Model 通过model向页面传递数据),若是页面是多个表单元素使用同一个name,那么就可以直接使用String[]接收值,这个和别的框架一样。没啥特别的。如果是Date类型,则需要注册转换器了,否则会报错,如下:

1.@InitBinder

下面,创建了几个类:
package com.billstudy.springmvc.bean;

import java.util.Date;

/**
 * User Bean 
 * @author Bill
 * @since V1.0 2015/01/25
 */ 
public class User {
	
	private Integer id;
	private String name;
	private Integer age;
	private Boolean status;
	private Date birthday;
	
	public User() {
		// TODO Auto-generated constructor stub
	}

	public User(Integer id,String name, Integer age, Boolean status, Date birthday) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.status = status;
		this.birthday = birthday;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", age=" + age
				+ ", status=" + status + ", birthday=" + birthday + "]";
	}

	public Boolean getStatus() {
		return status;
	}

	public void setStatus(Boolean status) {
		this.status = status;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
	
	
}
package com.billstudy.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.billstudy.springmvc.bean.User;

/**
 * 配合User bean演示相关注解使用
 * @author Bill
 * @since V.10 2015/01/25
 */
@Controller
@RequestMapping("/user")
public class UserController {
	/**
	 * 测试用户信息注入
	 * @param user
	 */
	@RequestMapping("/userSave")
	public void userSave(User user){
		System.out.println(user);
	}
}

WebContent/user/userEdit.jsp

<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>






	
姓名
年龄
状态 checked value="true"/>true checked value="false"/>false
生日 '/>
操作

下面打开页面测试,会发现500异常,原因是Date转换不支持。


异常:
这个时候,@InitBinder派上用场了。
在UserController中加上如下代码:
@InitBinder /* register Date parse support*/
	public void bindBinbar(ServletRequestDataBinder binder){ 
		binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));/** true:允许为空 **/
	}

再测一把,将表单提交

页面会报404错误,这个我们不管,因为方法没有返回值,它找的默认路径,默认路径没有对应的jsp页面,我们的关注点在参数自动绑定这块。可以看到参数已经绑定了,但是存在乱码,解决乱码:在web.xml加入org.springframework.web.filter.CharacterEncodingFilter的支持,如下

   
	characterEncodingFilter
  	org.springframework.web.filter.CharacterEncodingFilter
  	
  		encoding 
  		UTF-8
  	
   
   
  
	characterEncodingFilter
	/*
  

若是get乱码则可以修改Tomcat/server.xml的编码,或者在代码中对具体中文参数进行ISO-8859-1 To UTF-8的方法,个人偏向修改Tomcat编码,简单省事。

加入Filter之后,效果如下:
可以看到,我的名字没有乱码了。 这里可以看出,springmvc会将表单中的name绑定到方法参数中,和struts2不同的是。这里没有用对象.属性的方式,当然这里也支持。那就是复杂对象里面包含复杂对象的时候。如下面这个类的定义:
package com.billstudy.springmvc.bean;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * List , Map , String[] Test Bean
 * @author Bill
 * @since V1.0 2015/01/25
 */
public class Other {
	
	private List tUsers;
	
	private Map tMaps;
	
	private String[] tStrs;
	
	private User mainUser;
	
	public List gettUsers() {
		return tUsers;
	}

	public void settUsers(List tUsers) {
		this.tUsers = tUsers;
	}

	public Map gettMaps() {
		return tMaps; 
	}

	public void settMaps(Map tMaps) {
		this.tMaps = tMaps;
	}

	public String[] gettStrs() {
		return tStrs;
	}

	public void settStrs(String[] tStrs) {
		this.tStrs = tStrs;
	}

	public Other(List tUsers, Map tMaps, String[] tStrs) {
		super();
		this.tUsers = tUsers;
		this.tMaps = tMaps;
		this.tStrs = tStrs;
	}

	public User getMainUser() {
		return mainUser;
	}

	public void setMainUser(User mainUser) {
		this.mainUser = mainUser;
	}
	public Other() {
	}
}
这个对象中包含了User对象,我们暂且把它称为复杂对象。那么在页面想要给这里面的user注入值时,就可以使用mainUser.name/mainUser.age的方式了。可以看到,里面还有List,Map,String[]等类型的属性,这个下面也对其参数绑定进行演示。
添加页面:/WebContent/user/injectTest.jsp
<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>






	

List test


姓名
年龄
状态 true false
生日

姓名
年龄
状态 true false
生日

姓名
年龄
状态 true false
生日

Map test


Map key flyName :
Map key flyAge :
Map key flyAddress :

String Array test


mainUser 填写

姓名
年龄
状态 true false
生日
操作

录入参数如下:

控制台输出如下:
List tUsers:[User [id=null, name=姓名1, age=10, status=false, birthday=Mon Nov 11 00:00:00 CST 1991], User [id=null, name=姓名2, age=22, status=true, birthday=Tue Nov 12 00:00:00 CST 1991], User [id=null, name=姓名3,
age=33, status=false, birthday=Wed Nov 13 00:00:00 CST 1991]]
Map tMaps:{flyAddress=上海, flyAge=20, flyName=飞机}
String[] tStrs:[数组值01, 数组值02, 数组值03, 数组值04]
User mianUser:User [id=null, name=mainUser用户, age=100, status=true, birthday=Sun Jan 03 00:00:00 CST 1993]

2.@RequestParam

绑定单个请求参数

value参数名字,即入参的请求参数名字,如value=“id表示请求的参数区中的名字为id的参数的值将传入;

required是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;

defaultValue默认值,表示如果请求中没有同名参数时的默认值

添加方法如下(报错的测试,大家可以自己去做):

/**
	 * 用了defaultValue,其实required=true也不会报错,因为有默认值。请求时需要将id的值以userId=xx的形式提交,会自动将值绑定到形参id中
	 * @param model
	 * @param id
	 * @return
	 */ 
	@RequestMapping("/requestParamTest")
	public String requestParamTest(Model model,@RequestParam(defaultValue="520",required=true,value="userId")String id){
		model.addAttribute("msg", "requestParamTest id:"+id); 
		return "/result";
	}

测试如下:

不传递值,使用默认值

传递值:

3.@RequestBody

@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上,下面演示将客户端传递过来的JSON转成Java对象。

要使用这个注解,需要先加入两个jar包(jackson-core-asl-1.9.11.jar,jackson-mapper-asl-1.9.11.jar),同时需要在springmvc-servlet.xml适配器中加入对jackson的支持,修改之后如下:

	
		
			 
				
					
				 
			
		


在UserController中加入方法:

/**
	 * 演示JSON 	TO Java Object
	 * @param user
	 */
	@RequestMapping("/requestBodyTest")
	public void requestBodyTest(@RequestBody User user){
		System.out.println("user:"+user);
	}

利用HttpRequest测试:


控制台输出:


4.@ResponseBody

该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端

加入方法如下:

测试效果:

5.@ModelAttribute

Model一般可以用于在方法中放置变量在View取值,这个注解可以帮助我们将一些通用的变量返回到View(页面)。很方便取值,如下演示。
添加如下三个方法,2个添加参数,1个直接跳转到指定页面。测试能否取值
方法:
/** 
	 * 将key 为citys的数组对象传递到页面
	 * @return
	 */
	@ModelAttribute("citys")
	public String[] getCitys(){
		return new String[]{"中国","美国","伊拉克","日本"};
	}
	/** 
	 * 将key 为users的List对象传递到页面
	 * @return
	 */
	@ModelAttribute("users")
	public List getUsers(){
		List users = new ArrayList(); 
		for (int i = 0; i < 3; i++) {
			// 构造函数 : User(Integer id,String name, Integer age, Boolean status, Date birthday)
			users.add(new User(i,"测试姓名"+i,10+i,true,Calendar.getInstance().getTime()));
		}
		return users; 
	}
	/**
	 * 直接跳转到页面,不存放任何数据
	 * @return
	 */ 
	@RequestMapping("/toShowValue") 
	public String toShowValue(){
		return "/showValue"; 
	}

页面:

<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>



测试ModelAttribute


	citys:
${city}
Users:
${user}

访问结果:

三、forward/redirect

转发/重定向。也就是在方法内部设置ViewName或者直接返回String时可以达到转发/重定向的效果。
转发:方式相当于“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址。转发并没有执行新的request和response,而是和转发前的请求共用一个request和response。所以转发前请求的参数在转发后仍然可以读取到
重定向:方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为转发后的地址,因为转发即执行了一个新的request和response。
使用演示:
/**
	 * 演示转发,重定向用法,看注释部分就好了
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public String demoForwardRedirect(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
		// request.getRequestDispatcher("").forward(request,response);	// 转发
		// return "forward:/xx/xx.jsp";									// 转发
		
		// response.sendRedirect("/xx/xx.jsp");							// 重定向
		// return "redirect:/xx/xx.jsp";								// 重定向
		return null;
	}

注解部分还有@CookieValue,@RequestHeader@RequestPart,这些就小伙伴们自己去研究看看吧。 哈哈,收工。读书去了

本文所有代码:点击下载本文代码

上面分享的这些注解你会用了吗? 这里是 热爱生活,热爱技术,喜欢交友的大彪
.

版权声明:本文为博主原创文章,未经博主允许不得转载。

递归文件夹并树形打印

今天,一个网友问了这个问题,下班后就动手写给他了,顺便记录下。哈哈,记得刚学Java那会儿写过这玩意。

package com.billstudy.demo;

import java.io.File;

/**
 * Folder recursion show 
 * @author Bill
 * @since V1.0 2015/01/22
 */
public class FileRecursion {
	public static void main(String[] args) {
		// source file direction 
		String sourceTargetFilePath = "E:/alibaba";
		
		File sourceTargetFile = new File(sourceTargetFilePath);
		
		System.out.println(sourceTargetFilePath);
		
		recursionFile(sourceTargetFile,0L);
		
	}

	/**
	 * recursion file 
	 * @param file
	 */
	private static void recursionFile(File file,long level) {
		if(file.isFile()){
			System.out.println(printFilePath(level) + file.getName());;
		}else{
			File[] files = file.listFiles();
			for (File innerFile : files) {
				System.out.println(printFilePath(level) + innerFile.getName());
				if(innerFile.isDirectory()){
					// continue recursion 
					level++;
					recursionFile(innerFile,level);
					level--;
				}
			}
		}
	}

	/**
	 * print file path by level 
	 * @param file
	 * @param level
	 */
	private static String printFilePath(long level) {
		StringBuilder tree = new StringBuilder("|--");
		for (int i = 0; i < level; i++)
			tree.append("|--");
		return tree.toString();
	}
}

 文件结构:


控制台输出

遇到文件夹就深入,否则就打印结束递归。 

版权声明:本文为博主原创文章,未经博主允许不得转载。

和大彪一起来学习-SpringMvc之第二回(控制器,适配器说明)

简述:

在上一篇文章中,我们学会了如何搭建一个简单SpringMvc HelloWorld程序,这篇文章主要是介绍一些常用的控制器,适配器学习和作用。

一、HandlerMapping处理器映射器

HandlerMapping 给前端控制器返回一个HandlerExecutionChain 对象
(包含一个Handler (后端控制器)对象、多个HandlerInterceptor 拦截器)对象。 

1).BeanNameUrlHandlerMapping Bean别名路径映射器

BeanNameUrl,通过类的命名名称我们是否发现了些什么?对,没错,就是通过配置bean的时候,bean的name作为访问其对应Controller的路径。一般可以和SimpleControllerHandlerAdapter配合使用,你如果把上一篇文章里面的例子自己写了遍的话,就会发现我们是用他们两个实现的。(源码中,就是实现了其父类AbstractDetectingUrlHandlerMapping
的determineUrlsForHandler方法,在方法中根据Bean Name注册处理器)

springmvc-servlet.xml 一般可以这么配置使用它:

	
	

2).SimpleUrlHandlerMapping 简单路径处理映射器

SimpleUrl,这个是比较有意思的映射器,就是将访问路径直接映射到具体Controller类的id,

通过查看源码我们会发现其实类中有个Map,用来存放注入进去的路径和Bean的相关信息,

然后通过其父类注册处理器处理相关请求,看看源码就能更好的理解了:

public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
	// 内部用了个map作为存放访问路径和beand的映射
	private final Map urlMap = new HashMap();
	// 由于这里有这个方法,那么我们在配置文件中就可以通过mappings,注入我们的数据
	public void setMappings(Properties mappings) {
		this.urlMap.putAll(mappings);
	}
	// 省略部分不相关方法....
	public void initApplicationContext() throws BeansException {
		super.initApplicationContext();
		registerHandlers(this.urlMap);
	}

	protected void registerHandlers(Map urlMap) throws BeansException {
		if (urlMap.isEmpty()) {
			logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
		}
		else {
			Iterator it = urlMap.keySet().iterator();
			while (it.hasNext()) {
				String url = (String) it.next();
				Object handler = urlMap.get(url);
				// 如果不是斜杠起始,那么带上斜杠
				if (!url.startsWith("/")) {
					url = "/" + url;
				}
				// 如果是字符串,那么处理掉空格,这个不错,小细节也值得我们学习,
				if (handler instanceof String) {
					handler = ((String) handler).trim();
				}
				// 调用父类 AbstractUrlHandlerMapping方法,进行URL路径注册处理器
				registerHandler(url, handler);
			}
		}
	}

}

springmvc-servlet.xml一般可以这么配置使用:


	
		
			
				hello_controller
				hello_controller
			
		
	

二、HandlerAdapter处理器适配器

HandlerAdapter会把后端控制器包装为一个适配器,支持多种类型的控制器开发,这里使用了适配器设计模式。

1).SimpleControllerHandlerAdapter简单控制器处理器适配器

简单控制器处理器适配器所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为Springmvc的后端控制器,分析源码我们可以更好地发现这一点。
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
	// 判断目标类是否实现了Controller接口,为进一步执行handle方法做预判断
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

	// 处理方法
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 使用简单,粗暴的方式 直接向上转型后执行 我们实现类bean里面的handleRequest方法,也就是Controller里面唯一的待实现方法。
		return ((Controller) handler).handleRequest(request, response);
	}
}

一般在配置文件中,直接配置该类即可支持实现了Controller接口的类正常使用

2).HttpRequestHandlerAdapter
Http请求处理器适配器

HTTP请求处理器适配器将http请求封装成HttpServletResquest 和HttpServletResponse对象,和servlet接口类似。

通过源码会发现这个和上面的SimpleController处理有点类似,上面是强转Controller,这里是强转HttpRequestHandler对象,

所以我们想要使用这个适配器时,应该怎么做呢?你可能通过对比学习发现了,对,就是写个bean实现HttpRequestHandler这个接口就好了。 

比较简单,有兴趣的同学自己先试着写一下,然后想进一步看看内部如何实现的话可以去读读该源码哦。

了,今天这些就是内容了,主要就是以上映射器和适配器的介绍了。

大彪在这里只是简单地列出了几个,其实springmvc给咱们提供了很多映射器和适配器

如果小伙伴有更多的时间想对这些更深入地学习,可以继续看看别的类实现,如下图:


推荐个学习框架小技巧,可以通过查看框架的api文档找到几个主要的类或者接口,

然后弄懂大概整个的框架模型和基本架构(springmvc 组件架构去看看第一回),然后再通过这些主要的类,和接口去学习。

其实像这种比较成熟的开源框架,类的命名和注释都是相当规范的,以及具体用的一些设计模式、代码哲学都是非常值得我们学习的。

写几个小例子,跑跑,打个断点跟着框架走上几次,忒爽了。

这些有时候比啃书来的实际多了,当然作为IT人,技术图书也是必不可缺的,好拉。 下一篇打算写写,springmvc里面重点:注解的使用。


简单说明什么是映射器,适配器:

映射器:就是根据DispatcherServlet 拿过来的用户请求某部分路径去寻找处理器(就是我们写的具体的某个方法)和一些拦截器

适配器:具体执行处理器的对象,将ModelAndView返回给DispatcherServlet渲染视图用的


映射器,适配器你会用了吗? 这里是 热爱生活,热爱技术,喜欢交友的大彪 .

版权声明:本文为博主原创文章,未经博主允许不得转载。

和大彪一起来学习-SpringMvc之第一回(框架了解和第一个SpringMvc程序)

题记:

从今天开始,每周至少更新两篇博客,把框架知识复习一遍,并以渐进的形式记录下来,一是为了自己以后复习起来方便,也为了Java初学者能更好地学会这些知识. 


一、Spring mvc介绍

Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring
Web Flow里面。
Spring 框架提供了构建 Web 应用程序的全功能 MVC
模块。使用 Spring 可插入的 MVC 架构,
可以选择是使用内置的 Spring Web 框架还可以是 Struts
这样的 Web 框架。
Spring web mvc和Struts2都属于表现层的框架,它是Spring框架的一部分,我们可以从Spring的整体结构中看得出来:


、Web mvc 结构示意图



说明

1、 用户发起request请求至控制器(Controller)控制接收用户请求的数据,委托给模型进行处理

2、 控制器通过模型(Model)处理数据并得到处理结果模型通常是指业务逻辑

3、 控制器将模型数据在视图(View)中展示web中模型无法将数据直接在视图上显示,需要通过控制器完成。如果在C/S应用中模型是可以将数据在视图中展示的。

4、 控制器将视图response响应给用户通过视图展示给用户要的数据或处理结果。

、Spring mvc 架构


1.流程说明

1、 用户发送请求至前端控制器DispatcherServlet

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器

5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、 Controller执行完成返回ModelAndView

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器

9、 ViewReslover解析后返回具体View

10、 DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户

2.组件说明

以下组件通常使用框架提供实现(也就是一般企业中实际开发能满足大部分需求):

DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。

HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。

ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。

下边两个组件通常情况下需要开发:

Handler:处理器,即后端控制器用controller表示。

View:视图,即展示给用户的界面,视图中通常需要标签语言展示模型数据。


四、SpringMvc for HelloWorld 程序

测试开发环境为:win7 + Eclipse + Tomcat7

1.创建项目


后面两个步骤,直接用默认的就好了。
建好的项目如下:

2.加入SpringMvc 相关 Jar包

我会在文章结尾处将博客所用jar放出一个百度云链接,方便大家下载。
选中全部,copy到项目中/springmvc_blog_001/WebContent/WEB-INF/lib 下。

3.编写Web.xml 配置控制器



	springmvc_blog_001

	

	
		springmvc
		org.springframework.web.servlet.DispatcherServlet
		
			contextConfigLocation
			classpath:springmvc-servlet.xml
		
		1
	
	
		springmvc
		*.action
	

	
		index.jsp
	

配置说明:

load-on-startup:表示servlet随服务启动;

url-pattern*.action的请交给DispatcherServlet处理。

contextConfigLocation:指定springmvc配置的加载位置,如果不指定则默认加WEB-INF/[DispatcherServlet Servlet 名字]-servlet.xml

4.编写SpringMvc配置文件

在WEB-INF下创建springmvc-servlet.xml文件

1).配置处理器映射器

在springmvc-servlet.xml文件配置如下:



说明:BeanNameUrlHandlerMapping:表示将定义的Bean名字作为请求的url,需要将编写的controller在spring容器中进行配置,且指定bean的name为请求的url,且必须以.action结尾

2).配置处理器适配器


说明
:SimpleControllerHandlerAdapter:即简单控制器处理适配器

所有实现了org.springframework.web.servlet.mvc.Controller 接口的Bean作为Springmvc的后端控制器。



3).配置视图解析器

说明:

InternalResourceViewResolver:支持JSP视图解析viewClassJstlView表示JSP模板页面需要使用JSTL标签库,所有classpath中必须包含jstl的相关jar 包;prefix suffix:查找视图页面的前缀和后缀,最终视图的址为:前缀+逻辑视图名+后缀,逻辑视图名需要在controller中返回ModelAndView指定,比如逻辑视图名为hello,则最终返回的jsp视图地址 “WEB-INF/jsp/hello.jsp”.这里为了第一个程序简单起见,省略部分配置。

4).完整的配置是这样的



		
		
		
		
		
		
		
		
		
		
		
		

5. 开发后端控制器(Controller)

package com.billstudy.springmvc.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/**
 * HelloWorld 控制器
 * @author Bill
 * @since V1.0 2014/01/14
 */
public class HelloWorldController implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		
		// 存值
		modelAndView.addObject("testMessage", "hi,第一个SpringMvc程序!");
		
		// 设置跳转的页面(视图:View)
		modelAndView.setViewName("WEB-INF/helloworld.jsp");
		
		return modelAndView;
	}
}


6. 在springmvb-servlet.xml中加入自己写的HelloWorldController配置


		

7.编写jsp页面

在WEB-INF下面创建helloworld.jsp文件
好了,现在部署到Tomcat测试一把!
的,没有问题!
如果大家在启动项目时候出现,springmvc-servlet.xml找不到错误
请到Tomcat发布目录中看看spring-servlet.xml位置是否在classes中,可能因为Eclipse和Tomcat配置的不同,
位置也不一样。可以通过红色代码来配置对应的位置。
		
			contextConfigLocation
			classpath:springmvc-servlet.xml
		

所有源码+jar包百度云地址:点击打开链接

SpringMvc HelloWorld 你会了吗? 这里是
热爱生活,热爱技术,喜欢交友的大彪 .

版权声明:本文为博主原创文章,未经博主允许不得转载。

多浏览器Pre标签兼容样式

写好的样式,发现在火狐里面不换行,换下面的样式就好了. 

pre { 
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
-moz-binding: url('./wordwrap.xml#wordwrap'); 
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

spring:quartz 简单例子

 建立一个时序调度程序的过程如下:
    1) 配置Job及JobDetail Bean,定义执行某个类里的特定方法;
    2) 配置Trigger Bean,定义触发JobDetail的时间规律;
    3) 配置SchedulerFactoryBean负责调度实际的Trigger;时序调度的运行模式有两种:
    1) 一种是在某个特定时间自动运行,例如每天凌晨2点备份数据、每月初1号统计上月的数据等,我们称之为定时调度;

    2)另一种是在服务启动一段时间后开始运行,再每隔一段时间再次运行,如系统监控程序每个10分钟就要测试一下数据库是否连接正常,我们称之为重复调度;

配置文件:




           
    

	
	
	
	
	
	 
		
			
				
					
						
							
								
							
							
								quartzMethod_001
							
						
					 
					
				 
				
				
					
						
							
								
							
							
								quartzMethod_002
							 
						
					 
					
				
				
				
					
						
							
								
							
							
								quartzMethod_003
							
						
					 
					
				
			 
		
	

Job类:

/**
* 文件名:CommJob.java
* 版权:Copyright 2014-2015 BuyanTech.All Rights Reserved.
* 描述: 调度任务类
* 修改人:Bill
* 修改时间:2014/11/20
* 修改内容: 无
*/
package javacommon.util;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import org.springframework.beans.factory.annotation.Autowired;

import com.buyantech.campaign.service.CarUserManager;
/**
 * 普通调度任务类,将系统中需要调度的方法放到此类中
 * @author Bill
 * @since V1.0 2014/01/09
 */
public class CommJob {
	
	@Autowired
	private CarUserManager carUserManager;
	
	private static long quartzMethodCount001 = 0;
	private static long quartzMethodCount002 = 0;
	private static long quartzMethodCount003 = 0;
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); 
	
	public void quartzMethod_001(){
		System.out.println("CommJob.quartzMethod_001():"+getCurDateOfFormat() + " 调度 "+ ( quartzMethodCount001 ++) +"  次 !" );  
	}
	
	
	public void quartzMethod_002(){
		System.out.println("CommJob.quartzMethod_002():"+getCurDateOfFormat() + " 调度 "+ ( quartzMethodCount002 ++) +"  次 !" );
	}
	
	public void quartzMethod_003(){
		System.out.println("CommJob.quartzMethod_003():"+getCurDateOfFormat() + " 调度 "+ ( quartzMethodCount003 ++) +"  次 !" );
	}
	
	
	
	// 返回当前时间
	public String getCurDateOfFormat(){
		return sdf.format(Calendar.getInstance().getTime());
	}
}

简单例子,spring配置文件我用的内部bean,根据个人爱好吧…

版权声明:本文为博主原创文章,未经博主允许不得转载。

Java生成二维码实现扫描次数统计并转发到某个地址

需求:近几天某个项目需要用户录入个自己的网址,然后系统需要根据用户的的网址生成二维码,然后用户可以拿着它给别人扫描,访问到他录入的网址,在这个过程中.我需要知道用户的二维码被扫描的次数,也就是后面根据其可以做一些扫描排名之类的.

思路:

  1. 先生成二维码,csdn已经有前辈写了,那么我就直接拿过来用了. 
  2. 将用户的id,和用户录入的网址处理之后作为http get参数封装到二维码中,然后用户扫描会自动跳转到我们系统的某个接口
  3. 在接口中根据用户id将用户查询出来,扫描次数加1后重定向到用户录入页面
代码实现:
1.生成二维码部分,引用了前辈的成果,点个赞,用起来感觉不错!
package javacommon.qrcode;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import javax.imageio.ImageIO;

import org.junit.Test;

import jp.sourceforge.qrcode.QRCodeDecoder;
import jp.sourceforge.qrcode.exception.DecodingFailedException;

import com.swetake.util.Qrcode;
/**
 * 创建二维码工具类,将类改成了静态工具类
 * @author Bill
 * @see 源来自: http://blog.csdn.net/wangpeng047/article/details/7181217
 * @since V1.0 2014/01/07
 */
public class TwoDimensionCode {
	/*private TwoDimensionCode() {
	}*/
	
	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param imgPath 图片路径
	 */
	public static void encoderQRCode(String content, String imgPath) {
		encoderQRCode(content, imgPath, "png", 7);
	}
	
	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param output 输出流
	 */
	public static void encoderQRCode(String content, OutputStream output) {
		encoderQRCode(content, output, "png", 7);
	}
	
	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param imgPath 图片路径
	 * @param imgType 图片类型
	 */
	public static void encoderQRCode(String content, String imgPath, String imgType) {
		encoderQRCode(content, imgPath, imgType, 7);
	}
	
	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param output 输出流
	 * @param imgType 图片类型
	 */
	public static void encoderQRCode(String content, OutputStream output, String imgType) {
		encoderQRCode(content, output, imgType, 7);
	}

	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param imgPath 图片路径
	 * @param imgType 图片类型
	 * @param size 二维码尺寸
	 */
	public static void encoderQRCode(String content, String imgPath, String imgType, int size) {
		try {
			BufferedImage bufImg = qRCodeCommon(content, imgType, size);
			
			File imgFile = new File(imgPath);
			// 生成二维码QRCode图片
			ImageIO.write(bufImg, imgType, imgFile);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param output 输出流
	 * @param imgType 图片类型
	 * @param size 二维码尺寸
	 */
	public static void encoderQRCode(String content, OutputStream output, String imgType, int size) {
		try {
			BufferedImage bufImg = qRCodeCommon(content, imgType, size);
			// 生成二维码QRCode图片
			ImageIO.write(bufImg, imgType, output);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 生成二维码(QRCode)图片的公共方法
	 * @param content 存储内容
	 * @param imgType 图片类型
	 * @param size 二维码尺寸  取值范围1-40,值越大尺寸越大,可存储的信息越大
	 * @return
	 */
	private static BufferedImage qRCodeCommon(String content, String imgType, int size) {
		BufferedImage bufImg = null;
		try {
			Qrcode qrcodeHandler = new Qrcode();
			// 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小
			qrcodeHandler.setQrcodeErrorCorrect('M');
			qrcodeHandler.setQrcodeEncodeMode('B');
			// 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大
			qrcodeHandler.setQrcodeVersion(size);
			// 获得内容的字节数组,设置编码格式
			byte[] contentBytes = content.getBytes("utf-8");
			// 图片尺寸
			int imgSize = 67 + 12 * (size - 1);
			bufImg = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB);
			Graphics2D gs = bufImg.createGraphics();
			// 设置背景颜色
			gs.setBackground(Color.WHITE);
			gs.clearRect(0, 0, imgSize, imgSize);

			// 设定图像颜色> BLACK
			gs.setColor(Color.BLACK);
			// 设置偏移量,不设置可能导致解析出错
			int pixoff = 2;
			// 输出内容> 二维码
			if (contentBytes.length > 0 && contentBytes.length < 800) {
				boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);
				for (int i = 0; i < codeOut.length; i++) {
					for (int j = 0; j < codeOut.length; j++) {
						if (codeOut[j][i]) {
							gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);
						}
					}
				}
			} else {
				throw new Exception("QRCode content bytes length = " + contentBytes.length + " not in [0, 800].");
			}
			gs.dispose();
			bufImg.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bufImg;
	}
	
	/**
	 * 解析二维码(QRCode)
	 * @param imgPath 图片路径
	 * @return
	 */
	public static String decoderQRCode(String imgPath) {
		// QRCode 二维码图片的文件
		File imageFile = new File(imgPath);
		BufferedImage bufImg = null;
		String content = null;
		try {
			bufImg = ImageIO.read(imageFile);
			QRCodeDecoder decoder = new QRCodeDecoder();
			content = new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), "utf-8"); 
		} catch (IOException e) {
			System.out.println("Error: " + e.getMessage());
			e.printStackTrace();
		} catch (DecodingFailedException dfe) {
			System.out.println("Error: " + dfe.getMessage());
			dfe.printStackTrace();
		}
		return content;
	}
	
	/**
	 * 解析二维码(QRCode)
	 * @param input 输入流
	 * @return
	 */
	public static String decoderQRCode(InputStream input) {
		BufferedImage bufImg = null;
		String content = null;
		try {
			bufImg = ImageIO.read(input);
			QRCodeDecoder decoder = new QRCodeDecoder();
			content = new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), "utf-8"); 
		} catch (IOException e) {
			System.out.println("Error: " + e.getMessage());
			e.printStackTrace();
		} catch (DecodingFailedException dfe) {
			System.out.println("Error: " + dfe.getMessage());
			dfe.printStackTrace();
		}
		return content;
	}

	public static void main(String[] args) {
		String imgPath = "E:/01.png";
		//String encoderContent = "Hello 大大、小小,welcome to QRCode!" + "\nMyblog [ http://sjsky.iteye.com ]" + "\nEMail [ sjsky007@gmail.com ]";
		TwoDimensionCode handler = new TwoDimensionCode();
		//handler.encoderQRCode(encoderContent, imgPath, "png");
//		try {
//			OutputStream output = new FileOutputStream(imgPath);
//			handler.encoderQRCode(content, output);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
		// System.out.println("========encoder success");
		
		
		String decoderContent = handler.decoderQRCode(imgPath);
		System.out.println("解析结果如下:");
		System.out.println(decoderContent);
		System.out.println("========decoder success!!!");
	}
	
	@Test
	public void test01() throws UnsupportedEncodingException{
		String msg = "http://baike.baidu.com/link?YVWkHK4xQVWK444yX444yXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5ZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHK4n4aZGWU6z5sMY35SyXZxQMYVWkHKIkmbrHT9-s2WBaEbS哈哈哪里拉萨的";
		System.out.println("normal:"+msg.length());
		System.out.println("bytes:"+msg.getBytes("UTF-8").length);
		encoderQRCode(msg.toString(),"E:/2/t7.png", "png", 40);
		System.out.println("ok");
	}
}

package javacommon.qrcode;

import java.awt.image.BufferedImage;

import jp.sourceforge.qrcode.data.QRCodeImage;

public class TwoDimensionCodeImage implements QRCodeImage {

	BufferedImage bufImg;
	
	public TwoDimensionCodeImage(BufferedImage bufImg) {
		this.bufImg = bufImg;
	}
	
	@Override
	public int getHeight() {
		return bufImg.getHeight();
	}

	@Override
	public int getPixel(int x, int y) {
		return bufImg.getRGB(x, y);
	}

	@Override
	public int getWidth() {
		return bufImg.getWidth();
	}

}
还有个jar包,附上下载地址:http://pan.baidu.com/s/1jGmoshK
2.生成二维码并且提供外网访问地址方法
	/**
	 * 根据用户给的地址,生成一个二维码,并存放到本地. 返回出外网访问地址
	 * @param qrCodeTargetUrl	 用户传入的地址
	 * @param campaign	活动编号
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	private String generator2Code(String qrCodeTargetUrl,Campaign campaign) throws UnsupportedEncodingException {
		// TODO 实现二维码创建
		if(!StringUtils.isEmpty(qrCodeTargetUrl)){
			String httpUrl = AppConfig.getProperty("fileVisitUrl");
			String localUrl = AppConfig.getProperty("uploadFileBasePath");
			
			// 文件名
			StringBuilder userOfUrl = new StringBuilder("qrcode/");
			userOfUrl.append(campaign.getUser().getEmail() + "/");
			userOfUrl.append(campaign.get_id() + "/");
			
			new File(localUrl + userOfUrl).mkdirs();	// 创建文件夹
			
			userOfUrl.append("qrcode.png");
			
			// 生成扫描地址
			StringBuilder qrcodeScannerUrl = new StringBuilder();
			{
				qrcodeScannerUrl.append(AppConfig.getProperty("qrcodeScannerUrl"));
				qrcodeScannerUrl.append("t="+URLEncoder.encode(qrCodeTargetUrl, "UTF-8"));
				qrcodeScannerUrl.append("&i="+campaign.get_id());
			}
			
			long targetUrlLength = qrcodeScannerUrl.toString().getBytes("UTF-8").length;
			int qrcodeSize = 0;
			
			// 控制生成的二维码大小
			if(targetUrlLength <= 120 ){  		// 7
				qrcodeSize = 7;
			}else if(targetUrlLength <= 410){	// 15
				qrcodeSize = 15;
			}else{
				qrcodeSize = 20;		// 这里最大20已经能满足需要了,最大可以设置为40
			}
			
			TwoDimensionCode.encoderQRCode(
					qrcodeScannerUrl.toString(), 
					localUrl + userOfUrl,
					"png", 
					qrcodeSize);
			return httpUrl + userOfUrl; 
			
		}
		return StringUtils.EMPTY;
	}

3.扫描生成的所有的二维码会访问的接口,在这里进行扫描统计.
/**
* 文件名:QrcodeController.java
* 版权:Copyright 2014-2015 BuyanTech.All Rights Reserved.
* 描述: 负责累加广告的扫描次数
* 修改人:Bill
* 修改时间:2014/01/07
* 修改内容: 无
*/package com.buyantech.campaign.controller;

import java.io.IOException;

import javacommon.base.BaseSpringController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import com.buyantech.campaign.model.Campaign;
import com.buyantech.campaign.service.CampaignManager;
import com.buyantech.campaign.util.AppConfig;

/**
 * 负责累加广告的扫描次数
 * @author Bill
 * @since V1.0 2014/01/07
 */
@Controller
public class QrcodeController extends BaseSpringController {
	
	@Autowired
	private CampaignManager campaignManager;
	
	Logger logger = Logger.getLogger(QrcodeController.class);
	
	/**
	 * 用作增加广告二维码扫描次数,和转发
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void q(HttpServletRequest request,HttpServletResponse response) throws IOException{
		String targetUrl = request.getParameter("t");		// targerUrl : 目标地址
		String camId = request.getParameter("i");		// camId	 : 广告编号
		
		boolean isAddSuccess = false;
		int scannerSize = -1;
		if(!StringUtils.isEmpty(camId)){
			Campaign campaign = campaignManager.findById(camId);
			if (campaign != null) { 
				scannerSize = campaign.getQrCodeScanCount() + 1;
				campaign.setQrCodeScanCount(scannerSize);
				isAddSuccess = true;
				campaignManager.save(campaign);
			}
		}
		
		// 判断是否累加成功
		if(!isAddSuccess){
			logger.error("用户扫描目标二维码地址为:"+targetUrl+",扫描累加记录失败!");
		}else{
			logger.info("广告编号:"+camId+"被扫描,当前累积次数为:"+scannerSize);
		}
		
		// 判断是否携带地址,理论上是不存在地址为空的.可能被hacker恶意修改,友好提示!
		if(!StringUtils.isEmpty(targetUrl)){ 
			response.sendRedirect(targetUrl);
		}else{
			response.getWriter().print("

tips:感谢您扫描本次二维码,地址已经失效了,欢迎您访问:物联网广告平台

"); } } }

好的,到这里就差不多了. 

版权声明:本文为博主原创文章,未经博主允许不得转载。