Wednesday, October 15, 2014

แสดง captcha ด้วย jcaptcha v.1.0 และปัญหาไม่แสดงภาพ

เนื่องจากผมต้องการ captcha มาไว้ในเว็บเพื่อป้องกัน bot ต่างเข้ามาพิมพ์โน่นพิมพ์นี่เอง ทำให้ต้องหาๆๆๆ และก็หา เลยไปเจอ jcaptcha v 1.0 ตามลิ้งค์นี้เลย http://jcaptcha.sourceforge.net/ ดาวน์โหลดมาเลย
ผมโหลด v 1.0 พอดีมีอยู่เวอร์ชั่นเดียวสงสัยไม่พัฒนาต่อแล้วแหละ และตามด้วย  commons-logging และ commons-collection เอาไฟล์ .jar ทั้งสามไป add ใน Library ใน Netbean (ผมพัฒนาด้วย Netbean ครับ) เสร็จแล้วก็ขั้นตอนต่อไป

กำหนด servlet mapping ในไฟล์ dwr ดังนี้

เสร็จแล้วก็ไปขั้นตอนสร้าง servlet ต่อไปครับ โดยผมสร้าง java package JCaptchaService ขั้นมาข้างในประกอบไปด้วย 3 Class ด้วยกันคือ
1. CaptchaServiceSingleton
2. ImageCaptchaServlet ซึ่งเป็น Servlet
3. validateJCaptcha สร้างขึ้นมาเองเอาไว้ตรวจสอบเวลาใช้งานกับ DWR
โดย 2 Class แรก copy มาจากเขาเลยดังนี้
1.CaptchaServiceSingleton
package JCaptchaService;

import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

/**
 *
 * @author Nonpatan
 */
public class CaptchaServiceSingleton {
    private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();

    public static ImageCaptchaService getInstance(){
        return instance;
    }
}
2. ImageCaptchaServlet
public class ImageCaptchaServlet extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * GET and
     * POST methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        byte[] captchaChallengeAsJpeg = null;
       // the output stream to render the captcha image as jpeg into
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
        // get the session id that will identify the generated captcha.
        //the same id must be used to validate the response, the session id is a good candidate!
        String captchaId = request.getSession().getId();
        // call the ImageCaptchaService getChallenge method
            BufferedImage challenge =
                    CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId,
                            request.getLocale());
            //ImageIO.write(challenge, "jpeg", jpegOutputStream);
            // a jpeg encoder
            JPEGImageEncoder jpegEncoder =
                    JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }

        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();

        // flush it in the response
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream =
                response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
3. validateJCaptcha
public class validateJCaptcha {
    public boolean validate(String captchaId,String value){
        Boolean isResponseCorrect =Boolean.FALSE;
        try {
                isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId,
                        value);
            } catch (CaptchaServiceException e) {
            }
        
        return isResponseCorrect;
    }
    
}
ก็เป็นอันเสร็จนะครับ ในการเพิ่ม คลาส ต่อไปจะเป็นส่วนแสดงภาพ captcha กัน

ผมทำจะทำร่วมด้วยกับ javascript + dwr นะครับฉนั้นจะต้องแสดงประกอบไปด้วย ส่วน dwr จะไม่อธิบายในนี้นะครับ
นี่คือส่วนแสดงภาพนะครับ
ต่อไปส่วนใส่ตัวอักษรที่เห็นนะ


ต่อไปคือส่วนเปลี่ยนภาพในกรณีที่ดูภาพไ่ม่ออกอยากจะเอาภาพใหม่


จะเห็นว่าในส่วนเปลี่ยนภาพใหม่นั้นจะมีการเรียก javascript ด้วยคือ reloadImg(); ดังนั้นก็ต้องไปสร้าง javascript เพื่อเปลี่ยนภาพด้วยดังนี้
function reloadImg() {
            var d = new Date();
            document.getElementById("jcap").src = "/webPackage ของคุณ/jcaptcha?a=" + d.getTime();
        }
จะเห็นว่าจะต้องใช้ date(); เพื่อหลอกให้มันเปลียนภาพ
เสร็จแล้วต่อไปก็จะเป็นส่วนของการตรวจสอบว่าสิ่งที่พิมพ์ไปใน textbox นั้นตรงกับภาพหรือไม่ครับดังนี้
แต่ส่วนนี้จะเป็นหน้าที่ของ DWR ด้วยคือผมจะนำมาไม่หมดทั้ง function นะหลักๆก็ตามไฮไลน์สี่เขียวนะ
นอกนั้นจะเป็นในส่วนของ callback function ซึ่งเป็นเนื่อหาของ DWR
function validateForm(){
        //ทำการตรวจสอบ captcha
        var sid = "<%=(String)request.getSession().getId() %>";
        var valueCap = dwr.util.getValue("japtcha");
        if(valueCap===''){
            alert("Please fill charactor");
            var japtcha = dwr.util.byId("japtcha");
            japtcha.focus();
        }
        else{
            //ทำการตรวจสอบ captcha ก่อนเลยว่าถูกหรือไม่
            validateJCaptcha.validate(sid,valueCap,{
                callback:function(ok){
จะเห็นไว้ว่าในส่วนสีเขียว จะดึง sessionid มาเก็บไว้ที่ sid และดึงค่าที่ผู้ใช้เว็บป้อนมาทาง textbox มาเก็บไว้ที่ valueCap จากนั้นนำค่าทั้งสองไปให้ฟังก็ชั้นที่สร้างเองชื่อว่า validateJCaptcha.validate() ตามที่ได้สร้างไว้ก่อนหน้านี้ในข้อ 3 ถ้าตรงก็จะ return true ถ้าไม่ตรงก็จะ return false ครับผม จบยังเนี่ย เกือบจบแต่ไม่จบ
คือว่าเมื่อเสร็จแล้วผมก็นำขึ้นโฮสต์แต่ว่าไม่แสดงภาพเหมือนที่ทำกับ Notebook ที่บ้านเลย จึงถามโฮสต์ว่าใช้ jvm เวอร์ชั่นไหนก็ตอบมาว่า version 7 ผมใช้ version 6 และตอนที่ built ใน netbean มันก็บอกว่า JPEGCodec จะยกเลิกใช้แล้วก็เลยสงสัยว่าจะเป็นที่คลาสเนี่ยแหละที่ทำให้ไม่เห็นภาพมันอาจจะยกเลิกไปแล้วใน java 7 ผมก็เลยถ้างั้นหาตัวอื่นก็ได้เลยไปหามาคือ simple captcha ก็ง่ายดีแต่ก็มีปัญหากับ DWR อีกคือจะต้องส่ง session object ของ captcha ไปตรวจสอบที่ validate function ซึ่งส่งยากมากทำๆไปก็ไม่ได้ซักกะทีใครรู้บอกผมด้วยละกันส่งยังไง ก็เลยงั้นกลับมาแก้โค๊ดของ jcaptcha ก็ได้ซึ่งพอทำจริงๆก็ไม่ยากครับ ลองดูใน code ของ 2 นะที่ผมทำสีแดงและ comment เอาไว้หนะ เอา comment ออก และในส่วนของสีชมพูในข้อ 2 ก็ลบออกเลยครับ เสร็จจริงๆแล้วคราวนี้ครับผม สรุปว่าที่ไม่ขึ้นภาพเพราะ JPEGCodec ถูกยกเลิกไปแล้วครับผม

Monday, October 13, 2014

ส่งเมลส์ด้วย javaMail ผ่าน gmail

วันนี้ได้ทดลองส่งเมลส์ด้วย javaMail ดู แต่ก่อนหน้านี้ก็ได้ลองทำแล้วแต่ใช้ mail ที่ localhost
เริ่มเลยละกัน ออ ผมใช้ netbean นะครับ ฉนั้นพวก import เนี่ยผมไม่พูดละกันมันหาให้เองแหละ

-การจะติดต่อได้ก็ต้องมี API ก่อนนะ ผมใช้ javaMail คือมีทั้ง javax.mail และ activation หาโหลดเองนะครับ ผมลืมแล้วว่าเว็บไหน ปรึกษา google ได้เลย จากนั้นก็เอาไปไว้ที่ WEB-INF\lib

-จากนั้นก็เขียน code กัน อันนี้เป็นที่ผมทำไว้ใน web นะครับ ใช้ได้เลย(ลองในเครื่องตัวเองนะ)
การใช้ javaMail นั้นมีอยู่ด้วยกัน 3 แบบนะ ปกติ smtp จะเป็น port 25 นะ แต่ gmail.com จะใ้ห้เราใช้ port อื่น เพราะต้องใช้ Authen ด้วย
1. ใช้ smtp ไม่ใช้ Authen
2. ใช้ smtp ใช้ TLS Authen
3. ใช้ smtp ใช้ SSL Authen

สำหรับ gmail.com จะใช้ได้ทั้ง TLS และ SSL นะครับ สำหรับผมใช้แบบ TLS Authen

        String auth_host = "smtp.gmail.com";//กำหนด host
        String auth_port = "587";//กำหนด port
        final String auth_email = "satravel@gmail.com";//กำหนด email
        final String auth_password = "password";//กำหนด password

       // Get system properties object
        Properties properties = System.getProperties();

       // Setup mail server โดยใช้ TLS Authentication
        properties.put("mail.smtp.host", auth_host);
        properties.put("mail.smtp.port", auth_port);
        properties.put("mail.smtp.auth", "true");
        properties.put("mail.smtp.starttls.enable", "true");

        try {
         
            Authenticator auth = new Authenticator(){
                @Override
                public PasswordAuthentication getPasswordAuthentication(){
                    return new PasswordAuthentication(auth_email,auth_password);
                }
            };
         
            Session mailSession = Session.getInstance( properties , auth);//สร้าง session
            // Create a default MimeMessage object.
            MimeMessage message = new MimeMessage(mailSession);
            // Set From: header field of the header.
            message.setFrom(new InternetAddress(from,"Budsatravel"));//กำหนดชื่อผู้ส่งนะ
            //Set Reply To
            message.setReplyTo(InternetAddress.parse("satravel@gmail.com",false));//กำหนด reply
            // Set To: header field of the header.
            message.addRecipient(Message.RecipientType.TO,new InternetAddress(to,false));//ผู้รับ
            // Set Subject: header field
            message.setSubject("Booking From Budsatravel.com");//หัวข้ออีเมลส์
            // Now set the actual message
            message.setContent(content,"text/html");//ส่งเป็น html โดย content จะต้องมีลักษณะเป็น html
         
            // Send message
            Transport.send(message);
            return true;
        } catch (Exception mex) {
            return false;
        }

       เรียบร้อยครับผม
       ออในส่วนของ conten ตัวอย่างเช่น content = หัวข้อ ประมาณนี้ครับผม

      ข้อควรระวังอีกอย่าง ปิดการทำงานของ antivirus ด้วย ไม่งั้นอาจจะมีปัญหาเกี่ยวกับ Authen ได้ครับ