In this blog I will give a simple example on how to use a captcha in ABAP Webdynpro.
We generate a simple string in ABAP and send it to a servlet on a J2EE server. This servlet generates an image with SimpleCaptcha. http://simplecaptcha.sourceforge.net/ . The generated images is received on the ABAP stack and copied to a cached response so the captchastring is not in the url of the image.
The source of the java application can be downloaded here. (tested on SAP NW 7.31 SP5)
This is a simple servlet application that generates a captcha image from a given string.
1. Download the simplecaptcha library
2. Create an external library DC and name it captcha/lib
3. Add the simplecaptcha jar-file to the libraries folder
4. Add the jar-files to the public part of the library
5. Create a new web module development component and name it captcha
6. Add a DC dependency between the web module and the library
7. Add a new servlet and give it a name and package
8. Copy the simplecaptcha.jar to the WEB-INF/lib directory
9. Enter the following code:
package com.flexso.captcha;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.flexso.captcha.noise.CustomNoiseProducer;
import nl.captcha.Captcha;
import nl.captcha.servlet.CaptchaServletUtil;
import java.awt.Color;
import java.awt.Font;
public class CaptchaImage extends HttpServlet {
private static final long serialVersionUID = 1L;
private static int _width = 180;
private static int _height = 60;
private static final List<Color> COLORS = new ArrayList<Color>(2);
private static final List<Font> FONTS = new ArrayList<Font>(3);
static {
COLORS.add(Color.BLACK);
COLORS.add(Color.BLUE);
FONTS.add(new Font("Geneva", 2, 48));
FONTS.add(new Font("Courier", 1, 48));
FONTS.add(new Font("Arial", 1, 48));
}
public CaptchaImage() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("image/png");
response.setCharacterEncoding("UTF-8");
String word = request.getParameter("captcha");
WordGenerator wordRenderer = new WordGenerator(word);
Captcha captcha = new Captcha.Builder(_width, _height).addText(wordRenderer)
.gimp()
.addNoise())
.build();
CaptchaServletUtil.writeImage(response, captcha.getImage());
}
}
10. Add a class WordGenerator to be able to decide which word will be used to generate the captcha image.
package com.flexso.captcha;
import nl.captcha.text.producer.TextProducer;
public class WordGenerator implements TextProducer
{
private String text = "";
public WordGenerator(String text){
this.text = text;
}
public String getText(){
return this.text;
}
}
11. Adapt the web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>LocalDevelopment~captcha~flexso.com</display-name>
<servlet>
<description></description>
<display-name>CaptchaImage</display-name>
<servlet-name>CaptchaImage</servlet-name>
<servlet-class>com.flexso.captcha.CaptchaImage</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CaptchaImage</servlet-name>
<url-pattern>/captcha.png</url-pattern>
</servlet-mapping>
</web-app>
12. Create an enterprise application DC with the name captcha/ear
13. Add the web module to the captcha/ear project
14. Adapt the application.xml
<?xml version="1.0" encoding="ASCII"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_5.xsd" version="5">
<display-name>LocalDevelopment~captcha~ear~flexso.com</display-name>
<module>
<web>
<web-uri>flexso.com~captcha.war</web-uri>
<context-root>captcha</context-root>
</web>
</module>
</application>
15. Deploy the ear file.
16. Test the captcha http://<portalserver>:<port>/captcha/captcha.png?captcha=test
In the ABAP WD application we build a random string to send to the captcha application.
We request the captcha image on the ABAP server and provide it in a cached response to our webdynpro application to hide the captcha string in the url.
1. Create a new web dynpro component
2. In the component controller create a context node CAPTCHA with 3 strings: SOURCE, ANSWER, IMAGE.
3. Create method generate_captcha in the component controller. In this method we create a random string, with this string we build the url to the J2EE server to generate the captcha image. At the end of the method we copy the image from the java server to a cached response on the ABAP stack and then we fill the context. This is the code:
method GENERATE_CAPTCHA .
CONSTANTS: CO_ALFABET type CHAR30 VALUE 'abcdefghijklmnopqrstuvwxyz'.
DATA: lv_captcha type CHAR08,
lv_i type i,
lv_char type CHAR01,
lv_seed type i,
lo_ran type ref to cl_abap_random_int,
lv_url type string,
lv_length type i value 8.
* generate a random string with length lv_length
lv_seed = sy-timlo.
lv_i = STRLEN( co_alfabet ) - 1.
lo_ran = cl_abap_random_int=>create( min = 0 max = lv_i seed = lv_seed ).
DO lv_length TIMES.
lv_i = lo_ran->get_next( ).
lv_char = CO_ALFABET+lv_i(1).
lv_i = lo_ran->get_next( ).
if lv_i MOD 2 = 0 .
TRANSLATE lv_char TO UPPER CASE.
endif.
CONCATENATE lv_captcha lv_char into lv_captcha.
ENDDO.
* build url to generate captcha image
CONCATENATE '/captcha/captcha.png?captcha=' lv_captcha into lv_url.
lv_url = wd_this->GET_CACHED_URL( lv_url ).
" Set data in context
DATA lo_nd_captcha TYPE REF TO if_wd_context_node.
DATA lo_el_captcha TYPE REF TO if_wd_context_element.
DATA ls_captcha TYPE wd_this->Element_captcha.
lo_nd_captcha = wd_context->get_child_node( name = wd_this->wdctx_captcha ).
lo_el_captcha = lo_nd_captcha->get_element( ).
lo_el_captcha->set_attribute( name = `SOURCE` value = lv_captcha ).
lo_el_captcha->set_attribute( name = `IMAGE` value = lv_url ).
endmethod.
4. To copy the image from the JAVA response to the ABAP response I created a separate method GET_CACHED_URL. Importing parameter IV_URL (STRING) and returning parameter OV_URL(STRING)
method GET_CACHED_URL .
DATA : lo_http_client TYPE REF TO if_http_client,
lo_cached_response TYPE REF TO IF_HTTP_RESPONSE,
lv_image TYPE xstring,
lv_guid TYPE GUID_32.
" read the image on the java server
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = 'http://<javaserver>:<port>'
IMPORTING
client = lo_http_client
EXCEPTIONS
OTHERS = 1.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = '~request_uri'
value = iv_url.
CALL METHOD lo_http_client->send
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3.
CALL METHOD lo_http_client->receive
EXCEPTIONS
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3.
lv_image = lo_http_client->response->get_data( ).
" send the image to the cached response on the ABAP server
CREATE OBJECT lo_cached_response TYPE CL_HTTP_RESPONSE EXPORTING ADD_C_MSG = 1.
" SET IMAGE TO MIME
lo_cached_response->SET_DATA( lv_image ).
lo_cached_response->SET_HEADER_FIELD( NAME = IF_HTTP_HEADER_FIELDS=>CONTENT_TYPE VALUE = 'image/png' ).
lo_cached_response->SET_STATUS( CODE = 200 REASON = 'OK' ).
lo_cached_response->SERVER_CACHE_EXPIRE_REL( EXPIRES_REL = 100 ).
" generate an url
CALL FUNCTION 'GUID_CREATE'
IMPORTING
EV_GUID_32 = lv_guid.
CL_WD_UTILITIES=>CONSTRUCT_WD_URL( EXPORTING
APPLICATION_NAME = 'Z_CAPTCHA' "WEBDYNPRO APPLICATION NAME
IMPORTING OUT_LOCAL_URL = OV_URL ).
CONCATENATE OV_URL '/' lv_guid sy-uzeit '.png' INTO OV_URL.
CL_HTTP_SERVER=>SERVER_CACHE_UPLOAD( URL = OV_URL RESPONSE = lo_CACHED_RESPONSE ).
endmethod.
5. Open the view of the webdynpro
6. In the context tab, bind the CAPTCHA node from the componentcontroller.
7. In the layout tab add following elements to the view:
a. An image and bind the source property to attribute IMAGE af the CAPTCHA node.
b. An input field and bind the property value to attribute ANSWER of the CAPTCHA node.
c. A button ‘check captcha’ and assign an action CHECK
d. A button refresh and assign an action REFRESH
8. Implement the 2 actionhandlers
method ONACTIONCHECK.
DATA lo_nd_captcha TYPE REF TO if_wd_context_node.
DATA lo_el_captcha TYPE REF TO if_wd_context_element.
DATA ls_captcha TYPE wd_this->Element_captcha.
* get message manager
data lo_api_controller type ref to if_wd_controller.
data lo_message_manager type ref to if_wd_message_manager.
data: lv_Str type string,
lv_text type string,
lv_type type I.
" read context
lo_nd_captcha = wd_context->get_child_node( name = wd_this->wdctx_captcha ).
lo_el_captcha = lo_nd_captcha->get_element( ).
lo_el_captcha->get_static_attributes( IMPORTING static_attributes = ls_captcha ).
" get message manager
lo_api_controller ?= wd_This->Wd_Get_Api( ).
CALL METHOD lo_api_controller->GET_MESSAGE_MANAGER
RECEIVING
MESSAGE_MANAGER = lo_message_manager
.
lv_type = IF_WD_MESSAGE_MANAGER=>CO_TYPE_ERROR.
lv_text = 'ERROR!'.
TRANSLATE LS_CAPTCHA-SOURCE TO UPPER CASE.
TRANSLATE LS_CAPTCHA-ANSWER TO UPPER CASE.
" compare captcha answer with the source
if LS_CAPTCHA-SOURCE = LS_CAPTCHA-ANSWER.
lv_type = IF_WD_MESSAGE_MANAGER=>CO_TYPE_STANDARD.
lv_text = 'OK!'.
endif.
* report message
CALL METHOD lo_message_manager->REPORT_MESSAGE
EXPORTING
MESSAGE_TEXT = lv_text
MESSAGE_TYPE = lv_type
RECEIVING
MESSAGE_ID = lv_str
.
endmethod.
method ONACTIONREFRESH .
WD_COMP_CONTROLLER->GENERATE_CAPTCHA( ).
endmethod.
Create a web dynpro application object and test the application!
Result:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Subject | Kudos |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
User | Count |
---|---|
13 | |
9 | |
7 | |
7 | |
7 | |
6 | |
5 | |
4 | |
4 | |
4 |