置顶随笔

[置顶]通过一个简单的登录过程了解Struts的业务流程(Struts初学的请进)

一个简单的登录过程描述了一下Struts的业务流程,感觉挺容易懂的,摘出来大家分享:(1)用户的请求以HTTP方式传输到服务器上,接收请求的是ActionServlet。
(2)ActionServlet接收到请求后,会查找struts-config.xml文件来确定服务器上是否有用户请求的操作,此处用户请求的操作应为登录操作。如果没有,则返回一个用户请求无效的出错信息。
(3)当ActionServlet找到用户请求的Action后,首先将用户输入的表单参数打包成一个ActionForm对象,这个ActionForm对象其实也就是一个JavaBean,里面包含两个字段,分别是用户名和密码。接着ActionServlet再根据struts-config.xml中的配置信息决定是否要执行ActionForm对象中的Validate方法。若Validate方法执行有错,则返回;否则,继续下一步。
(4)系统生成一个用户所请求的Action的实例对象,将前面的ActionForm对象传递给它,运行它的execute()方法。这一步其实就是用户登录的控制器,在执行execute()方法时,可以调用后台模型验证登录名和密码是否正确等信息。
(5)execute()执行结束前会生成一个ActionForward类型的对象并将之返回给ActionServlet,该对象的作用是告诉ActionServlet下一步应该跳转到哪里,假如后台模型检验用户名和密码正确,则ActionForward就代表跳转到一个登录成功的界面。ActionServlet将对之进行分析,其实就相当于接收到一个新的请求,重复(2)~(5)的过程,直到将某个界面返回用户为止。
以上就是Struts的基本工作流程,可以看出struts-config.xml在整个流程中起到了一个类似站点地图的作用,它记录了所有可能的请求跳转。其实,在Web容器加载Struts应用程序后,struts-config.xml就被首先读入内存成为一个ActionMapping对象,前面所说的查找struts-config.xml文件,实际上是查找ActionMapping对象。对于初学者来说可以不必深究其中的细节……
摘自清华大学出版社出版的《Struts-Web设计与开发大全》

posted @ 2008-04-04 23:27 伍兴佳 阅读(427) | 评论 (1)编辑 收藏

2008年5月16日

J2EE程序员之路之武功修为片

                                                         作者:EasyJF开源团队(www.easyjf.com) 大峡

  经常会跟一些朋友讨论怎么样才能学好Java,学到什么程度才算撑握了Java的问题。其中有一个J2EE程序员层次及武功修为的问题,有点意思。这里就把讨论的内容大致整理一下发出来,大家继续讨论。  纵观国内的软件行业,靠Java吃饭的程序员还真不是少,而且Java程序员是有很大优越感的,毕竟对于很多用b/s搞开发的业内朋友来说,Java技术意味着难度大、门槛高,因此相对来说Java程序员比其它的程序员(如php、.net)收入高就理所当然。然而J2EE所涉及到的范畴是很广的,不能一个Java程序员就概括了事,而应该具有层次及水平之分,很多时候经常需要进行分类或评级,有时他评、有时自评。  谈到国内J2EE领域的程序员层次水平,当前流行的称谓及评级不外乎就下面几种:  第一种是精通掌握记事本、Dreamweaver等工具来写JSP+JavaBean数据库应用的是J2EE程序员;
  第二种是用JBuilder、Eclipse等专用Java开发工具写着一堆一堆过程式Java Bean,而且还能精通Struts+Spring+Hibernate等应用框架的高级J2EE程序员;
  第三种是用Together建模,然后生成一堆Java接口或代码,开口闭口都是设计模式的资深Java程序同及高级系统分析、构架师;
  最后还有一种是整天在BlogJava或JavaEye上谈经论道的大师们,这些大师技术水平难以触摸,武功门派也各具特色,不好归类,有时不好称为程序员(因为有的时候他们甚至不写或者写不出程序),但又做着与J2EE程序员密切相关的事情,我们暂且就归为“牛牛”或“大师”。  称谓毕竟只是称谓,带有点主观或者功利色彩,有时很难鉴定一个人应该属于什么,因此,我们再从纯技术的角度,也即武功修为的角度,作了一个简单的分析及归类,把2EE领域程序员大致分成以下几个层次,可以作为大家自评的一个参考标准:  第一个层次:精通掌握Java语法、能调试基本的程序错误,精通掌握JSP+Java Bean写一些N年前ASP、PHP翻版的Java Web应用程序(如论坛、网站新闻发布系统、OA、网上商城等),精通JDBC使用、精通SQL语句、精通XML等。  第二个层次:掌握设计模式原理及应用,掌握基于OO的分析及设计方法,并能精通熟练使用几种Java专业设计及开发工具,精通掌握流行的J2EE框架如Hibernate、EJB、Webwork、Spring的原理及应用,精通J2EE中一两个组成部分(如Servlet、EJB等)的工作原理及细节。  第三个层次:少林的高僧有两种,禅僧及武僧。J2EE程序员的第三个层次也同样有禅、武两个分支,这里我们重点分析一下:  第一个分支属于走的禅僧线路。在练完第二个层次中的各种武功基础上,结合实际项目中的千奇百怪的用户需求,游刃有余的选择适合的技术方案为客户解决问题,并形成自己的一套解决方案。达到这一个层次的J2EE程序员已经不在乎使用任何工具、任何框架了,而是根据不同的对手,使用不同的武器或招式来应对。好比 小李飞刀一样,只有达到了“手中无刀、心中有刀”的境界,才能达到“出手一刀,例不虚发”的效果。这一层次的武功属于一个熟练度问题,刀练得多了、遇到的对手多了,再加上前面的武功修为,就算做不到例不虚发,也可达到十发九中。  第二个分支属于走的武僧线路,在撑握熟悉第一二个层次中涉及到的内容后,进一步专研并撑握J2EE底层开发,J2EE规范制订、规范实现、Java虚拟机的工作原理、各种常见的J2EE服务器内核工作机制、内存管理、进程机制、源代码等。因为涉及的很多东西都比较抽象,代码也很多,练这一层的武功需要有很好的资质及耐性、并具还得有一定的环境及条件。好比神雕大侠杨过拿起“玄铁剑”,并练成“暗然销魂掌”的成长过程,需要前面的武功修为作基础,更需那只威力神武神雕的帮助指点及他处处为民、惩奸除恶的侠之心态。
  
  胡侃了这么多,现在来根据自己情况测算一下自己的份量,结果如下:  第一层 练到8成;
  第二层 练到5成;
  第三层 准备走禅僧线路,当前算是练到1成;
  
  唉,后面的武功提升越来越难,真不知道要到何年何月才能达到10成啊。你的武功练到哪一个层次了,不防亮出来大家切磋切磋。嘿嘿,要是有一天,咱们中国的Java程序员人手一把“玄铁剑”、人人会使“暗然销魂掌”,那还了得!汗...,写着写着居然做起白日梦了,不好意思,就此打住。
  
  手中鸡蛋先别扔,还要打个广告:本人刚开始涉足Java开源,目前在EasyJF开源团队中负责EasyJWeb(官网www.easyjf.com)项目,欢迎大家前来指导。
       很牛的一个人物啊!

posted @ 2008-05-16 00:47 伍兴佳 阅读(211) | 评论 (0)编辑 收藏

2008年4月5日

纯JAVA技术验证码生成器(服务器端servlet实现)(不是javascript哦~)

java验证码生成器,自认为还算经典import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
* @(#)VerifyCodeServlet.java Dec 9, 2007 8:14:14 PM
*
* @author Yuan
* 验证码生成器,使用此类需要将表单里的验证码输入框的name属性设为"verifycode"
*/
public class VerifyCodeGenerator {
    
    private static final VerifyCodeGenerator generator = new VerifyCodeGenerator();
    
    private final String ATTRIBUTE_NAME = "verifycode";
    //图片的宽度
    private final int WIDTH = 15;
    //图片的高度
    private final int HEIGHT = 22;
    //字符串长度
    private final int CODE_LENGTH = 4;
    //随机字符串范围
    private final String RAND_RANGE = "abcdefghijklmnopqrstuvwxyz"
        + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        + "1234567890"
        + "@#quot;;
    
    private final char[] CHARS = RAND_RANGE.toCharArray();
    
    private Random random = new Random();
    
    private VerifyCodeGenerator(){
        //
    }
    
    public static VerifyCodeGenerator getInstance(){
        return generator;
    } 
     

    /**
     * 生成随机字符串
     * @return 随机字符串
     */
    private String getRandString(){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < CODE_LENGTH; i++)
            sb.append(CHARS[random.nextInt(CHARS.length)]);
        return sb.toString();
    }
    
    /**
     * 生成随机颜色
     * @param ll 产生颜色值下限(lower limit)
     * @param ul 产生颜色值上限(upper limit)
     * @return 生成的随机颜色对象
     */
    private Color getRandColor(int ll, int ul){
        if (ll > 255) ll = 255;
        if (ll < 1) ll = 1;
        if (ul > 255) ul = 255;
        if (ul < 1) ul = 1;
        if (ul == ll) ul = ll + 1;
        int r = random.nextInt(ul - ll) + ll;
        int g = random.nextInt(ul - ll) + ll;
        int b = random.nextInt(ul - ll) + ll;
        Color color = new Color(r,g,b);
        return color;
    }
    
    /**
     * 生成指定字符串的图像数据
     * @param verifyCode 即将被打印的随机字符串
     * @return 生成的图像数据
     * */
    private BufferedImage getImage(String verifyCode){
        
        BufferedImage image = new BufferedImage(WIDTH * CODE_LENGTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        
        //获取图形上下文
        Graphics graphics = image.getGraphics();
        
        //设置背景色
        graphics.setColor(getRandColor(1,50));
        //填充背景色
        graphics.fillRect(0, 0, WIDTH * 4, HEIGHT);
        
        //设置边框颜色
        graphics.setColor(new Color(0,255,0));
        //画边框
        for (int i=0; i<2; i++)
            graphics.drawRect(i, i, WIDTH * CODE_LENGTH - i * 2 - 1, HEIGHT - i * 2 - 1);
        
        //设置随机干扰线条颜色
        graphics.setColor(getRandColor(50,100));
        //产生50条干扰线条
        for (int i=0; i<50; i++){
            int x1 = random.nextInt(WIDTH * CODE_LENGTH - 4) + 2;
            int y1 = random.nextInt(HEIGHT - 4) + 2;
            int x2 = random.nextInt(WIDTH * CODE_LENGTH - 2 - x1) + x1;
            int y2 = y1;
            graphics.drawLine(x1, y1, x2, y2);
        }
        
        //设置字体
        graphics.setFont(new Font("Times New Roman", Font.PLAIN, 18));
        //画字符串
        for (int i=0; i<this.CODE_LENGTH; i++){
            String temp = verifyCode.substring(i, i+1);
            graphics.setColor(getRandColor(100,255));
            graphics.drawString(temp, 13 * i + 6, 16);
        } 
         
        //图像生效
        graphics.dispose();
        
        return image;
    }
    
    /**
     * 将验证码的图像输出
     * @param request 用户的请求对象
     * @param response 用户的响应对象
     * */
    public void printImage(HttpServletRequest request,
            HttpServletResponse response){
        //将ContentType设为"image/jpeg",让浏览器识别图像格式。
        response.setContentType("image/jpeg");
        //设置页面不缓存
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 2000);
        
        //获得随机验证码
        String verifyCode = this.getRandString();
        String str = "ssss";
        for(int i=0; i<10; i++)
            str = str + str;
        //获得验证码的图像数据
        BufferedImage bi = this.getImage(verifyCode);
        //把验证码存入session
        request.getSession().setAttribute(ATTRIBUTE_NAME, verifyCode);
        try{
            //获得Servlet输出流
            ServletOutputStream outStream = response.getOutputStream();
            //创建可用来将图像数据编码为JPEG数据流的编码器
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outStream);
            //将图像数据进行编码
            encoder.encode(bi);
            //强行将缓冲区的内容输入到页面
            outStream.flush();
            //关闭输出流
            outStream.close();
        }catch(IOException ex){
            ex.printStackTrace();
        }
    }
    
    /**
     * 检查输入的验证码是否正确,若用户输入的验证码与生成的验证码相符则返回true,否则返回false。
     * @param request 用户的请求对象
     * @return 验证结果
     * */
    public boolean check(HttpServletRequest request){
        if (((String)request.getParameter(ATTRIBUTE_NAME))
                .equalsIgnoreCase((String)request.getSession().getAttribute(ATTRIBUTE_NAME))){
            request.getSession().removeAttribute(ATTRIBUTE_NAME);
            return true;
        }
        return false;
    }
}
/**此代码为我们群老大深秋小雨
所编写,真的比较实用,来自qq群J道
**/

posted @ 2008-04-05 12:40 伍兴佳 阅读(5427) | 评论 (10)编辑 收藏

一个小脚本测试

为什么我写的一个显示系统时间的小脚本不能在这里显示出来?
还有就是如何使用DOM的getelementbyid方法显示系统时间?
<SCRIPT LANGUAGE="JavaScript">
<!--
var timerID = null
var timerRunning = false
function showtime(){
  var today,hour,second,minute,year,month,date;
var strDate ;
today=new Date();
var n_day = today.getDay();
switch (n_day)
 {
case 0:{
strDate = "星期日"
       }break;
case 1:{
strDate = "星期一"
       }break;
case 2:{
strDate ="星期二"
       }break;
case 3:{
strDate = "星期三"
       }break;
case 4:{
strDate = "星期四"
       }break;
case 5:{
strDate = "星期五"
       }break;
case 6:{
strDate = "星期六"
       }break;
case 7:{
strDate = "星期日"
       }break;
}
year = today.getYear();
month = today.getMonth()+1;
date = today.getDate();
hour = today.getHours();
minute =today.getMinutes();
second = today.getSeconds();
if(month<10) month="0"+month;
if(date<10) date="0"+date;
if(hour<10) hour="0"+hour;
if(minute<10) minute="0"+minute;
if(second<10) second="0"+second;
 timeValue =year + " 年 " + month + " 月 " + date + " 日 " + strDate +" " + hour + ":" + minute + ":" + second
   document.GG.MM.value = timeValue
   wuxingjia= setTimeout("showtime()",1000)
 
}

//-->
</SCRIPT>
</HEAD> <BODY onLoad="showtime()">
<FORM NAME="GG" onSubmit="0">
   <INPUT TYPE="text" NAME="MM" SIZE=40 >
</FORM>

posted @ 2008-04-05 01:18 伍兴佳 阅读(838) | 评论 (3)编辑 收藏

sqlserver中,sql编程的几个小常识 呵呵,容易出错的~

sqlserver中,sql编程的几个小常识

1、取出刚刚插入(删除)的数据SELECT 字段名 FROM INSERTED(DELETED)
2、对于UPDATE实际上是先DELETE然后再INSERT所以如果想得到UPDATE前后的数据值,应该先从DELETED取出,然后从INSERTED取出;
3、IF UPDATE(列名)可以判断更新或插入哪一个字段的值;
4、@@ROWCOUNT可以判断上一行查询操作得到的列数;
5、给变量赋值用SET @ZQB = 13;
6、察看是否有符合条件的记录IF EXISTS (SELECT name FROM sysobjects WHERE name = 'reminder' AND type = 'TR');
7、定义游标,如下:
DECLARE c1 CURSOR FOR
SELECT emp_mgr.emp
FROM emp_mgr, inserted
WHERE emp_mgr.emp = inserted.mgr

OPEN c1
FETCH NEXT FROM c1 INTO @e--从游标中取出数据
WHILE @@fetch_status = 0--判断是否到最后
BEGIN
UPDATE emp_mgr
SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Add 1 for newly
WHERE emp_mgr.emp = @e -- added employee.

FETCH NEXT FROM c1 INTO @e
END
CLOSE c1
DEALLOCATE c1--删除游标引用

posted @ 2008-04-05 00:38 伍兴佳 阅读(986) | 评论 (2)编辑 收藏

关于隐式挖掘网站用户行为的分析

关于隐式挖掘网站用户行为的分析如何了解用户和需求

  如何了解用户需求?根据用户是否主动参与分为显式与隐式两种挖掘模式,因为显式的动静比较大,有很大局限性,所以为了保证结果准确性以及提高用户接受度,一般都采用隐式。

  用户的日常交互行为会产生四类关键数据:鼠标移动轨迹、链接点击分布、页面浏览流、页面停留时间。通过用户的行为能反映用户的观点,同时利用访问的网页次序可以找出网页之间的隐性关系。

  收集数据

  Web服务器的日志(用户会话记录)

  Web trends或类似的第三方共享软件(客户端分析,流量分析,可用性分析)

  自己开发的第三方软件/插件(需求自定义)


  大型网站通常会把以上三种方法组合应用,大致原理就是给进入网站的用户赋予身份识别,每次产生交互动作就向服务器发回请求,通过时间和页面判断连接各个请求点并且记录下来。(算法不讨论)

  过滤数据

  明确目标,定义核心数据。

  界定用户行为,利用多数人的行为来消除个人行为的主观性。

  对用户进行归类,确定数据类别。

  大型网站每天所产生的数据量是惊人的,所以常规需求一般都是定时或定量的分析。另外,额外的数据处理会减慢网站的速度,搜集的数据越多,潜在的负面影响越大。

  习惯分析

  对用户浏览过的页面进行内容分析,根据信息主题对页面进行聚类。

  聚类过程中除了考虑页面内容相近程度,还应该考虑页面路径。

  把用户浏览行为对其兴趣的作用列入聚类结果,得到综合评估模型。

  用户兴趣分偶然和稳定两种情况,其中偶然可以认为是随机变化的,稳定的挖掘又有基于内容和行为两种方式,在内容上表现有重复度、相似度等,在行为上表现有停留时长、点此次数、拉动滚动条次数等。

  实际案例

  类似系统、浏览器、分辨率的客户端分析,常见而且简单,略过。

  关于鼠标轨迹、点击分布的可用性例子:

  跟踪用户在进行检索时的鼠标移动轨迹,可以获取用户操作的先后顺序、热点功能、动作曲线等一手数据,这些都是改善或简化表单的重要参考。
在重要的页面进行详细的点击分布监控统计,主要检查信息呈现的易用性,看看有没有偏离设计初衷,经常更新,找到规律。

  处理特定用户行为、用户群、用户来路的任务流例子:

  监控分布式注册流程,能够看到有多少用户填了表单、填完了表单,或者在某个步骤有异常流失。


  监控不同模块入口过来的注册用户,能够统计出各模块导入的有效注册量、百分比、成功率,以便合理调配资源。

  监控投放广告过来的注册量、注册成功率、转换付费用户成功率,以便明确广告的投入产出比。

  监控用户的纵深浏览行为,是测试导航可用性很好的办法,也就是说用户会不会在你的网站内迷路。

posted @ 2008-04-05 00:06 伍兴佳 阅读(1125) | 评论 (7)编辑 收藏

2008年4月4日

通过一个简单的登录过程了解Struts的业务流程(Struts初学的请进)

一个简单的登录过程描述了一下Struts的业务流程,感觉挺容易懂的,摘出来大家分享:(1)用户的请求以HTTP方式传输到服务器上,接收请求的是ActionServlet。
(2)ActionServlet接收到请求后,会查找struts-config.xml文件来确定服务器上是否有用户请求的操作,此处用户请求的操作应为登录操作。如果没有,则返回一个用户请求无效的出错信息。
(3)当ActionServlet找到用户请求的Action后,首先将用户输入的表单参数打包成一个ActionForm对象,这个ActionForm对象其实也就是一个JavaBean,里面包含两个字段,分别是用户名和密码。接着ActionServlet再根据struts-config.xml中的配置信息决定是否要执行ActionForm对象中的Validate方法。若Validate方法执行有错,则返回;否则,继续下一步。
(4)系统生成一个用户所请求的Action的实例对象,将前面的ActionForm对象传递给它,运行它的execute()方法。这一步其实就是用户登录的控制器,在执行execute()方法时,可以调用后台模型验证登录名和密码是否正确等信息。
(5)execute()执行结束前会生成一个ActionForward类型的对象并将之返回给ActionServlet,该对象的作用是告诉ActionServlet下一步应该跳转到哪里,假如后台模型检验用户名和密码正确,则ActionForward就代表跳转到一个登录成功的界面。ActionServlet将对之进行分析,其实就相当于接收到一个新的请求,重复(2)~(5)的过程,直到将某个界面返回用户为止。
以上就是Struts的基本工作流程,可以看出struts-config.xml在整个流程中起到了一个类似站点地图的作用,它记录了所有可能的请求跳转。其实,在Web容器加载Struts应用程序后,struts-config.xml就被首先读入内存成为一个ActionMapping对象,前面所说的查找struts-config.xml文件,实际上是查找ActionMapping对象。对于初学者来说可以不必深究其中的细节……
摘自清华大学出版社出版的《Struts-Web设计与开发大全》

posted @ 2008-04-04 23:27 伍兴佳 阅读(427) | 评论 (1)编辑 收藏

仅列出标题  
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

导航

统计

公告

这是伍嗲的纯JAVA技术博客

常用链接

留言簿(1)

随笔档案

文章分类

相册

技术链接

搜索

最新评论

阅读排行榜

评论排行榜