Wednesday, May 27, 2015

Select one unique record from DB table with the latest date

I have a file_store table like below.



I would like to select the latest records for each filetype_id.



The SQL to do this can be like this.

 SELECT f.file_id,f.FILETYPE_ID, f.file_obj_l,max_date  
 FROM FILE_STORE f inner JOIN   
 (SELECT FILETYPE_ID, max(f1.UPDATETS) as max_date FROM FILE_STORE f1  
 where FILETYPE_ID in (1, 2, 3)   
  group by FILETYPE_ID  
 ) a  
 on a.FILETYPE_ID = f.FILETYPE_ID and a.max_date = f.UPDATETS  



Tuesday, May 26, 2015

How to submit form with file upload field to Spring MVC controller?

Here is a very simple example on how to submit form with file upload field to Spring mvc.



1. Make sure you have org.apache.commons.fileupload.FileItemFactory in your library.
I have two blogs on how to add this jar into jboss environment.
http://jijli.blogspot.com/2015/04/jboss-module-dependency-error-caused-by.html
http://jijli.blogspot.com/2015/05/how-to-add-jar-in-maven-project-in.html

2. Add the following in Spring servlet-context.xml.

 <!-- Enable this for eventual integration of file upload functionality-->  
 <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">  
  <!-- setting maximum upload size -->  
  <property name="maxUploadSize" value="20000000"/>   
 </bean>  

3. HTML form.

 <html>  
 <head>  
 <title>Upload File Request Page</title>  
 </head>  
 <body>  
      <form method="POST" action="uploadFile" enctype="multipart/form-data">  
           File to upload: <input type="file" name="file"><br /> <br />  
           Name: <input type="text" name="name"><br /> <br />   
           <input type="submit" value="Upload"> Press here to upload the file!  
      </form>  
 </body>  
 </html>  


4. Spring MVC controller

 import java.io.BufferedOutputStream;  
 import java.io.File;  
 import java.io.FileOutputStream;  
 import org.slf4j.Logger;  
 import org.slf4j.LoggerFactory;  
 import org.springframework.stereotype.Controller;  
 import org.springframework.ui.ModelMap;  
 import org.springframework.web.bind.annotation.RequestMapping;  
 import org.springframework.web.bind.annotation.RequestMethod;  
 import org.springframework.web.bind.annotation.RequestParam;  
 import org.springframework.web.bind.annotation.ResponseBody;  
 import org.springframework.web.multipart.MultipartFile;  
 /**  
  * Handles requests for the application file upload requests  
  */  
 @Controller  
 public class FileUploadController {  
      private static final Logger logger = LoggerFactory  
                .getLogger(FileUploadController.class);  
      @RequestMapping(value = "/uploadFile", method = RequestMethod.GET )  
      public String uploadfile(ModelMap model)  
      {  
           return "upload";  
      }       
      /**  
       * Upload file using Spring Controller  
       */  
      @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)  
      public @ResponseBody  
      String uploadFileHandler(@RequestParam("name") String name,  
                @RequestParam("file") MultipartFile file) {  
           if (!file.isEmpty()) {  
                try {  
                     byte[] bytes = file.getBytes();  
                     // Creating the directory to store file  
                     String rootPath = System.getProperty("catalina.home");  
                     File dir = new File(rootPath + File.separator + "tmpFiles");  
                     if (!dir.exists())  
                          dir.mkdirs();  
                     // Create the file on server  
                     File serverFile = new File(dir.getAbsolutePath()  
                               + File.separator + name);  
                     BufferedOutputStream stream = new BufferedOutputStream(  
                               new FileOutputStream(serverFile));  
                     stream.write(bytes);  
                     stream.close();  
                     logger.info("Server File Location="  
                               + serverFile.getAbsolutePath());  
                     return "You successfully uploaded file=" + name;  
                } catch (Exception e) {  
                     return "You failed to upload " + name + " => " + e.getMessage();  
                }  
           } else {  
                return "You failed to upload " + name  
                          + " because the file was empty.";  
           }  
      }  
 }  




Wednesday, May 20, 2015

How to test a web service with an attachment by using SoapUI?

"SoapUI is a free and open source cross-platform Functional Testing solution. With an easy-to-use graphical interface, and enterprise-class features, SoapUI allows you to easily and rapidly create and execute automated functional, regression, compliance, and load tests. " 

You can download it and more information from http://www.soapui.org/ .

Here is an example I am using it to test a web service with an attachment.

1. Create a SOAP Project.



2. Right click on the project- test, then choose Add WSDL.








3. Now I am going to send a request with an attachment to the service.
    Double click on Request1 on left side, then there is Request 1 window showing on the right side.
    Click on the Attachment.





4. Click on the button in red circle, then choose the file to attach.



5. Click the run button in red circle. Now you can see the result.



Tuesday, May 19, 2015

How to pass multiple checkbox (checked and unchecked) values to server side?

 In the W3C HTML 4, it has something like this:
Checkboxes (and radio buttons) are on/off switches that may be toggled by the user. A switch is "on" when the control element's checked attribute is set. When a form is submitted, only "on" checkbox controls can become successful.

This means the value is only sent if the checkbox is checked. So we need to have a way of remembering what checkboxes you are expecting on the server side since not all the data comes back from the form.


In my case, I have same checkbox names in different rows. The HTML code is like this.

 <c:forEach items="${classes}" var="class">  
      <tr>  
           <td  
                class="hidden-xs hidden-sm hidden-md hidden-lg ui-state-default">  
                <input type="hidden" id="classid" name="classid[]"  
                value='<c:out value="${class.configClassId}"/>'></input> <input  
                type="hidden" id="displayOrder" name="displayOrder[]"  
                class="form-control"  
                value='<c:out value="${class.displayOrder}"/>'></input>  
           </td>  
           <td><input type="text" id="internalClassName"  
                name="internalClassName[]" class="form-control"  
                placeholder="Class Internal Name"  
                value='<c:out value="${class.internalClassName}"/>'></td>  
           <td><input type="text" id="displayName"  
                name="displayName[]" class="form-control"  
                placeholder="Display Name"  
                value='<c:out value="${class.displayName}"/>' /></td>  
           <td>  
                <div class="checkbox">  
                     <c:if test="${class.enable!=null && class.enable=='Y'}">  
                          <input type="checkbox" name="enabled[]"  
                               class="form-control chk" value="Y" checked="checked">  
                     </c:if>  
                     <c:if test="${class.enable==null || class.enable!='Y'}">  
                          <input type="checkbox" name="enabled[]"  
                               class="form-control chk" value="Y">  
                          <input type="hidden" name="enabled[]" class="chk" value="N">  
                     </c:if>  
                </div>  
           </td>  
           <td><input type="text" id="searchWeight[]"  
                name="searchWeight[]" class="form-control"  
                value='<c:out value="${class.searchWeight}"/>'></td>  
           <td><input type="hidden" id="fileid" name="fileid[]"  
                class="form-control"  
                value='<c:out value="${class.fileStore.fileId}"/>'><img  
                src="${pageContext.request.contextPath}/download/${class.fileStore.fileId}"></td>  
           <td>  
                <div class="input-group">  
                     <span class="input-group-btn"> <span  
                          class="btn btn-default btn-file active">  
                               Browse&hellip; <input type="file" id="uploadimage"  
                               name="uploadimage[]" class="form-control" multiple />  
                     </span>  
                     </span> <input type="text" class="form-control" readonly>  
                </div>  
           </td>  
           <td><button type="button" class="removebutton"  
                     title="Remove this class">  
                     <span class="glyphicon glyphicon-remove "></span>  
                </button></td>  
      </tr>  
 </c:forEach>  


Since it only sends the checked values, I couldn't find out which checkbox value match to which row.
In order to work around this, you can see in the html code, I added hidden input to set a value if the value from server side is not 'Y'.  (See highlighted code above.)

For checkbox is changed after the page is loaded, I added some javascript code to set the right value in. The javascript code is as below.


  .on("click", ".chk",function() {  
    var v = $(this).attr('checked') == 'checked'?'Y':'N';  
    if (v=='Y')  
     {  
     $(this).removeAttr('checked');   
     $(this).after('<input type="hidden" name="enabled[]" value="N" />');  
     }  
    if (v=='N')  
     {  
          $(this).attr('checked');   
          $(this).val( "Y" );  
          if ($(this).next().attr('class')=='chk')  
               $(this).next().attr('disabled', true);       
     }  
 }  


There must be some other ways to do this. But the code above works fine for me. It sent checked and unchecked values correctly to the server side.







Thursday, May 14, 2015

More examples on Bootstrap form validator

In the previous blog, I have some examples on how to use bootstrap form validation. These days I did some more validation by using bootstrap validation.  Here are the examples.



I would like to have Display Name less then 20 characters, and Search Weight field only can put 1 or 9.

The following highlighted code showed how to add the new validation items in. I used stringLength and regexp validator.

Also you may see, when the mouse is over the red cross on the error field, the error message is showing on top of it. The code for this used 'tooltip'. See the highlighted code below.


 $('#classconfigform')  
           .formValidation(  
                     {  
                          framework : 'bootstrap',  
                          err : {  
                               container : 'tooltip'  
                          },  
                          row : {  
                               selector : 'td'  
                          },  
                          icon : {  
                               valid : 'glyphicon glyphicon-ok',  
                               invalid : 'glyphicon glyphicon-remove',  
                               validating : 'glyphicon glyphicon-refresh'  
                          },  
                          fields : {  
                               'internalClassName[]' : {  
                                    validators : {  
                                         notEmpty : {  
                                              message : 'Internal class name is required'  
                                         }  
                                    }  
                               },  
                               'displayName[]' : {  
                                    validators : {  
                                         notEmpty : {  
                                              message : 'Display name is required'  
                                         },  
                                         stringLength: {  
                                              max: 20,  
                                              message: 'The display name must be less than 20 characters long.'  
                                              }  
                                    }  
                               },  
                               'searchWeight[]' : {  
                                    validators : {  
                                         notEmpty : {  
                                              message : 'Search Weight is required'  
                                         },  
                                         regexp: {  
                                              regexp: '^[19]+$',  
                                              message: 'Only 1 and 9 can be chosen. 1 for class always on top.'  
                                              }  
                                    }  
                               },  
                               'uploadimage[]' : {  
                                    validators : {  
                                         callback : {  
                                              message : 'An image is required',  
                                              callback : function(  
                                                        value,  
                                                        validator,  
                                                        $field) {  
                                                   var $fileid = '';  
                                                   var $classimg = $field  
                                                             .closest('tr');  
                                                   // console.log("classimg:"+$classimg );  
                                                   $fileid = $classimg  
                                                             .find(  
                                                                       '#fileid')  
                                                             .val();  
                                                   //console.log("fileid:"+$fileid);  
                                                   //console.log("upload img value:"+value);  
                                                   if (($fileid == null || $fileid == '')  
                                                             && (value == null || value == ''))  
                                                        return false;  
                                                   else  
                                                        return true;  
                                              }  
                                         },  
                                    //end of callback  
                                    stringLength: {  
                                              max: 30,  
                                              message: 'The file name must be less than 30 characters long.'  
                                              }  
                                    }  
                               }  
                          }  
                     })  








Monday, May 11, 2015

JPA exception: org.hibernate.PersistentObjectException: detached entity passed to persist

When I saved a collection of form data into database by using JPA, I got "detached entity passed to persist" error.

I have a CompanyClass entity, and inside CompanyClass entity, I have a one to one relationship to Filestore entity.  See detail relationship of these two entities at JPA relationship between entities.

The save method I wrote in my service impl is like following:

     @PersistenceContext   
     private EntityManager emgr; 
     @Override  
     @Transactional  
      public void saveClass(CompanyClass cclass)  
                throws Exception {  
           emgr.persist(cclass);  
           emgr.close();  
      }  


But when I ran it, I got exception: org.hibernate.PersistentObjectException: detached entity passed to persist.

After research, I found out I shouldn't use

 emgr.persist(cclass);  

Instead, I should use

  emgr.merge(cclass);  


I found a blog about JPA: persisting vs. merging entites . It is clear about when we should use persist, and when we should use merge.

In my case, it falls into this:

You want to insert a new entity that may have a reference to another entity that may but may not be created yet (relationship must be marked MERGE). For example, inserting a new photo with a reference to either a new or a preexisting album.


Wednesday, May 6, 2015

How to make file upload style to look same in all browsers?

I have a file upload feature in my application. I found it looks different in all different browsers if I just use <input type='file'>.





After some research, I found out a way to make it looks like a button with different styles by using Bootstrap.  It will display all the same in different browsers, and you can choose the right style that matches your design.



HTML code:

  <div class="input-group">                                                                                                           
            <span class="input-group-btn">                                                                                                       
                <span class="btn btn-success btn-file active">                                                                                             
                  Browse&hellip; <input type="file" id="uploadimage" name="uploadimage[]" class="form-control" multiple>                                                                 
                </span>                                                                                                                  
           </span>                                                                                                                   
   <input type="text" class="form-control" readonly>                                                                                              
 </div>                                                                                                                     

CSS:

 .btn-file {  
   position: relative;  
   overflow: hidden;  
 }  
 .btn-file input[type=file] {  
   position: absolute;  
   top: 0;  
   right: 0;  
   min-width: 100%;  
   min-height: 100%;  
   font-size: 100px;  
   text-align: right;  
   filter: alpha(opacity=0);  
   opacity: 0;  
   outline: none;  
   background: white;  
   cursor: inherit;  
   display: block;  
 }  
 input[readonly] {  
  background-color: white !important;  
  cursor: text !important;  
 }  


JS code:

 $(document).on('change', '.btn-file :file', function() {            
  var input = $(this),                             
    numFiles = input.get(0).files ? input.get(0).files.length : 1,      
    label = input.val().replace(/\\/g, '/').replace(/.*\//, '');       
  input.trigger('fileselect', [numFiles, label]);                
 });                                       
 $(document).ready( function() {                         
   $('.btn-file :file').on('fileselect', function(event, numFiles, label) {  
     var input = $(this).parents('.input-group').find(':text'),       
       log = numFiles > 1 ? numFiles + ' files selected' : label;     
     if( input.length ) {                          
       input.val(log);                           
     } else {                                
       if( log ) alert(log);                        
     }                                    
   });                                     
 });                                       






Friday, May 1, 2015

How to add a jar in Maven project in Jboss server?

In Jboss server, the repository is under {jboss root directory}\.m2\repository.

The configuration file is {jboss root directory}\.m2\setting.xml

There is a website called mvnrepository.com. It's a search engine for  jars, dependencies and repositories.

For example, I am searching for apache fileupload jar in mvnrepository.com. (See screenshot below.)



 I chose the latest version.



I copied the dependency, and put it into pom.xml.


In the pom.xml, the following lines are added.

  <dependency>  
           <groupId>commons-fileupload</groupId>  
           <artifactId>commons-fileupload</artifactId>  
           <version>1.3.1</version>  
           <scope>compile</scope>  
 </dependency>  

For the maven dependency scope, we can find detail information from here.


If this jar is not in your repository, you may download the jar and put it into your repository if you control it. Or you can right click download (jar) link to find out the repository from here, and add it into your setting.xml.

Note:
If the missing jar is a dependency from a module, then we have to add a new module instead. Reference previous blog.