通过验证码的设计来深入理解web项目中jsp与servlet的不同

12 篇文章 0 订阅
5 篇文章 0 订阅

我们都知道,在访问网站登陆的时候,会有输入验证码的情况,而且每次登陆所输入的验证码都不同,那么这是用什么实现的?

猜想1:直接写在jsp中,然后由servlet转发并呈现给用户

答:jsp一般是用来帮助我们编辑网页与java的,其本质上还是java,因为服务器在执行jsp的时候会将它翻译成一个与servlet几乎一样但是只是名字不同的一个接口实现类。那么jsp中是可以写java的,但是由于我们开发的web项目采用的是mvc模式,对数据进行运算放在数据库的相关工具类或者工厂类中,那么呈现出网页视图即向浏览器发送html则是jsp的任务,而servlet在这两者中间起到连接和传递的功能。我们知道验证码的生成其实是一个动态过程,每次请求访问都会返回一个不同的验证码,那么这种行为是不仅仅是显示图片那么简单,背后有着生成随机动态验证码的过程。那么如果我们把生成验证码的功能放在jsp中,就和mvc模式相违背。项目代码必定耦合度高,维护和复用性也会有所影响。虽然jsp脚本可以熟悉java,但是我们依然不能这么做。

猜想2 : 写在servlet中,由sevlet进行动态生成

答:这也是不对的,servlet作为处理http协议的组件,那么他的功能最好单一一些比较好,就是处理浏览器的请求并进行转发或者重定向。那么假设处理登陆功能的logservlet有输入验证码的功能,如果支付功能payservlet也要有输入验证码的功能,那么这段代码的复用性就成为了问题,耦合度也提高了。所以我们应当写在工具类中或者工厂类中,不过可以让servlet通过文件读写的字节流发送给浏览器。


上述是从mvc开发模式角度来分析这个问题,jsp一般用来呈现静态资源而servlet则是处理动态请求。那么验证码是动态的,所以从mvc开发模式角度分析,可以得出这个答案


那我们从浏览器运行html脚本的工作原理上来重新看待这个问题,是否能得出相同的结论呢?

我们附上浏览器加载网页的简易原理


假设我们的验证码就是图片img,当我们通过浏览器访问服务器,服务器通过jsp给我们返回的是一个html网页文件,浏览器开始加载网页并执行html语句给我们呈现出网页视图。这个过程是从上到下执行的,假设我们的验证码是img,处在用户和密码之后的位置,那么他会先加载用户和密码输入框,再加载验证码。那么当运行到img时,浏览器再向服务器发送请求,要求获取图片,但是这个图片是静态的而不是动态,所以不能用html的img标签来实现动态图片的展示。

所以我们要是想要向浏览器展示动态图片,只能用servlet来实现。当浏览器加载到验证码图片位置时,浏览器向服务器发送请求,这时候我们用一个imgservlet来处理浏览器需求验证码的请求,这个imgservlet则调用工厂类中的imgCreate方法构造一个动态图片,然后将这个动态图片通过字节流传输给浏览器。

从浏览器运行原理角度也能得出相应的结论,同时也是符合mvc模式设计原理。

package Cls; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; public class MyVerifyCode extends HttpServlet { private static MyVerifyCode instance; private final String ATTRIBUTE_NAME = "verifycode"; // ��֤���ַ������� private final int CODE_LENGTH =4; // ��֤��߶����� private static final int Height =30; // ������֤���Ƿ���Ҫ��תЧ�� private boolean ROTATE_FLAG = true; //���������Ƿ���Ҫ��� private boolean FONT_FLAG=false; //�����������Ĭ������ private String font=""; //��������Ĵ�С,Ĭ��Ϊ15 private int fontsize=15; private final String RAND_RANGE = "abcdefhgkmnpqrstuvwxyz" + "ABCDEFGHGKLMNPQRSTUVWXYZ" + "2345678"; // private Random rand=new Random(); public static Random rand = new Random(); private final char[] CHARS = RAND_RANGE.toCharArray(); // ���캯�� public MyVerifyCode() { } public static MyVerifyCode getInstance() { if (instance == null) instance = new MyVerifyCode(); return instance; } // �������ַ� private String getRandString() { StringBuffer vcode = new StringBuffer(); for (int i = 0; i < CODE_LENGTH; i++) vcode.append(CHARS[rand.nextInt(CHARS.length)]); return vcode.toString(); } // ��������� public static float getRandomJiao() { float jiao = 0.0f; if (rand.nextFloat()<=0.5) { jiao = rand.nextFloat()-0.3f; } else { jiao = -rand.nextFloat()+0.3f; } return jiao; } // ��������ɫ 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 = rand.nextInt(ul - ll) + ll; int g = rand.nextInt(ul - ll) + ll; int b = rand.nextInt(ul - ll) + ll; Color color = new Color(r, g, b); return color; } private BufferedImage getImage(HttpServletRequest request) { //根据设置的高度计算事宜的fontsize int FontSize=Height*75/96; //根据设置的字体及字的个数计算出适宜的宽度 int width = CODE_LENGTH * FontSize*4/5 + 10; //根据字体大小设置X轴的位移量 int X_=FontSize/2; BufferedImage image = new BufferedImage(width,Height, BufferedImage.TYPE_INT_RGB); // ��ȡͼ�������� Graphics graphics = image.getGraphics(); Graphics2D g2 = (Graphics2D) graphics; g2.setColor(getRandColor(100, 255)); g2.setColor(Color.WHITE); g2.fillRect(0, 0, width, Height); g2.translate(0, Height*2/3); double oldrot = 0; String vcode=this.getRandString(); // 把验证码存入session request.getSession(true).setAttribute("codes", vcode); for (int i = 0; i < CODE_LENGTH; i++) { g2.setFont(new Font("Times New Roman", Font.HANGING_BASELINE, FontSize)); double rot = getRandomJiao(); // 旋转画笔 if (ROTATE_FLAG) { g2.rotate(-oldrot); g2.translate(X_+rand.nextInt(8), 0); oldrot = rot; g2.rotate(rot); } String temp = vcode.substring(i, i + 1); g2.setColor(getRandColor(1, 100)); g2.drawString(temp, 0, 0); } // ͼ����Ч g2.dispose(); return image; } 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(); // �����֤���ͼ����� BufferedImage bi = this.getImage(request); try { // ���Servlet����� ServletOutputStream outStream = response.getOutputStream(); // ������������ͼ����ݱ���ΪJPEG������ı����� JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outStream); // ��ͼ����ݽ��б��� encoder.encode(bi); // ǿ�н���������������뵽ҳ�� outStream.flush(); // �ر������ outStream.close(); } catch (IOException ex) { ex.printStackTrace(); } } public void doGet(HttpServletRequest request, HttpServletResponse response) { printImage(request, response); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值