Http Compression

HTTP compression is a capability that can be built into web servers and web clients to improve transfer speed and bandwidth utilization.

HTTP data is compressed before it is sent from the server: compliant browsers will announce what methods are supported to the server before downloading the correct format; browsers that do not support compliant compression method will download uncompressed data.

The most common compression schemes include gzip and Deflate. This means that when it is in use, your bandwidth costs for serving the site, will be lower because people visiting the site will be downloading smaller files.

Using GZip, takes time and processor power to zip and unzip the files, but typically this is not a problem because the time it takes to do that, is often less than the time that is saved by downloading a smaller file. Therefore the overall effect is a time saving, despite the browser having to unzip the file.

Read More

Spring MVC Validation

In spring mvc, we can utilize JSR 303 and JSR 380 specification to make validation easier.

Note: If you already depend on spring-boot-starter-web, then you already have Spring Validation.

Otherwise, you’ll have to include spring-context.

Code

Read More

Http Cookie

An HTTP cookie is a small piece of data that a server sends to the user’s web browser.

The browser stores it(if it is enabled) and send it back to the same server in subsequent each request inside a Cookie HTTP header, even including requests for assets like images or CSS / JavaScript files.

Read More

Share Session In Multiple Web Project

Suppose there are two web projects: test4 and test5, the login page is in test4 and when user access resources of test5, he/she will be redirected to login page of test4 if he/she has not login yet.

Read More

Apache Shiro Hello World

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management.

Read More

Session

Http protocol is a stateless, that is each request is a new request.

Read More

Design Principles

There are 5 most recommended design principles when building your application. They are called S.O.L.I.D

Read More

Java Generics

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming.

The generics looks like:

  List<String> list = new ArrayList<>();
  //add item to list
  String s = list.get(0);

or

  public class Box<T> {
	    // T stands for "Type"
	    private T t;
      //other code
	}

The most commonly used type parameter names are:

  E - Element (used extensively by the Java Collections Framework)
  K - Key
  N - Number
  T - Type
  V - Value
  S,U,V etc. - 2nd, 3rd, 4th types

Wildcards

Read More

Java Interface And Abstract Class

Java Interface

  • an interface is implicitly abstract, so you do not need to use abstract keyword while declaring interface
  • all fields are automatically public, static and final
  • as of java 8, interface can define default method and static method, other methods are implicitly abstract, so the abstract modifier is unnecessary
  • methods in interface are implicitly public, cannot be other modifier
  • it can be declared public or package scope(no access modifier)
  • interface only can extends interface(one or more)
  • subclass needs to provide unimplementation methods
Read More

Json

Read More

Hash

hash salt

e.g. hash(“hello”) will generate hash value ‘2cf24dba5’, two same plain text have same hash values.

In order to create different hash values despite same original string as well as making hacker harder to steal password, we can randomize the hash by appending or prepending a random string, call a salt, to the password before hashing, for example, hash(“hello”+”abc123”), here abc123 is the salt.

In practice, the salt is stored in DB as a separate column or as part of the hash string itself.

The salt does not need to be secret.

For more details, please refer to this

Read More

Install Dokuwiki

What is dokuwiki

As its name implies, it is a wiki which can be used in a company to share knowldege.
It’s web-based and database is not required.

Another is MediaWiki.

System requirements:

  • web server, e.g. apache, ngnix, not tomcat
  • php >= 5.2
  • php-gd
Read More

Maven Connect To Private Repository

Take nexus oss 3 for example, maven settings.xml looks like:


<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

<servers>

<!-- used for deploy artifact to nexus release or snapshots repository -->
<server>
<id>nexus</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>

<mirrors>
<mirror>
<id>nexus</id>
<mirrorOf>*</mirrorOf>
<url>http://192.168.2.102:8081/repository/maven-public</url>
</mirror>
</mirrors>

<profiles>

<!-- set maven default java compiler version -->
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>

<profile>
<id>nexus</id>
<repositories>
<repository>
<id>central</id>
<url>http://central</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>http://central</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>

<activeProfiles>
<activeProfile>nexus</activeProfile>
</activeProfiles>

</settings>

<servers> tag is a list of authentication profiles, keyed by the server-id used within the system.  Authentication profiles can be used whenever maven must make a connection to a remote server.

<server> specifies the authentication information to use when connecting to a particular server, identified by a unique name within the system (referred to by the ‘id’ attribute below). NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are used together.

<mirrors>  is a list of mirrors to be used in downloading artifacts from remote repositories. It works like this: a POM may declare a repository to use in resolving certain artifacts. However, this repository may have problems with heavy traffic at times, so people have mirrored it to several places. That repository definition will have a unique id, so we can create a mirror reference for that repository, to be used as an alternate download site. The mirror site will be the preferred server for that repository.

<mirror> specifies a repository mirror site to use instead of a given repository. The repository that this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used for inheritance and direct lookup purposes, and must be unique across the set of mirrors.

profiles is a list of profiles which can be activated in a variety of ways, and which can modify the build process. Profiles provided in the settings.xml are intended to provide local machine-specific paths and repository locations which allow the build to work in the local environment. For example, if you have an integration testing plugin - like cactus - that needs to know where your Tomcat instance is installed, you can provide a variable here such that the variable is dereferenced during the build process to configure the cactus plugin. As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles section of this document (settings.xml) - will be discussed later. Another way essentially relies on the detection of a system property, either matching a particular value for the property, or merely testing its existence. Profiles can also be activated by JDK version prefix, where a value of ‘1.4’ might activate a profile when the build is executed on a JDK version of ‘1.4.2_07’. Finally, the list of active profiles can be specified directly from the command line. NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact repositories, plugin repositories, and free-form properties to be used as configuration variables for plugins in the POM.

profile Specifies a set of introductions to the build process, to be activated using one or more of the mechanisms described above. For inheritance purposes, and to activate profiles via <activatedProfiles/> or the command line, profiles have to have an ID that is unique. An encouraged best practice for profile identification is to use a consistent naming convention for profiles, such as ‘env-dev’, ‘env-test’, ‘env-production’, ‘user-jdcasey’, ‘user-brett’, etc. This will make it more intuitive to understand what the set of introduced profiles is attempting to accomplish, particularly when you only have a list of profile id’s for debug.

maven-public is a repository group.  From next screenshot, we can see that:

untitled-2

type of maven-public is group and it has three members: maven-releases, maven-snapshots and maven-central.

group means we can just use group(e.g.maven-public) in maven settings.xml to represent all its members, such that we don’t need to define all repository urls in settings.xml and  it will download jars from its members according to the definition order, e.g. maven-snapshots has a.jar, we use maven-public in settings.xml, then it can download a.jar from nexus.

However we cannot upload artifact to group.

maven-releases and maven-snapshots are hosted repository.  They are used for storing our own artifacts, for instance our company jars, or 3rd party which cannot downloaded from public maven repository.

maven-central is proxy repository which means nexus look for jars from it, if it has, then download jar from maven-central, if it has not, then download jar from public maven repository(https://repo1.maven.org/maven2/) and keep it in maven-central.

Upload own artifact to nexus by following configuration in project pom.xml:


<distributionManagement>
<repository>
<id>nexus</id>
<name>Releases</name>
<url>http://192.168.2.102:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus</id>
<name>Snapshot</name>
<url>http://192.168.2.102:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>

then run maven deploy command.

Read More

reverse proxy and forward proxy

  • forward proxy(some people call it client proxy)

(client -> forward proxy) -> target server

client cannot access target server directly, therefore use forward proxy to get client request and forward it to target.

client knows forward proxy and target server, while target server only knows forward proxy.

The client must be configured to use the forward proxy to access other sites.

It also can use caching to reduce the network usage.

  • reverse proxy(server proxy)

client -> (reverse proxy -> other server)

for client, it only knows reverse proxy and reverse proxy is target server for it, it just let other server to handle the client requests.

No configuration in client is necessary.

A typical usage is load balance

Read More

centos 7 build nexus oss maven server

Installation

  1. install oracle idk 8 and configure JAVA_HOME, make it as default
  2. download nexus oss 3.2
sudo tar xvzf nexus-3.2.0-01-unix.tar.gz -C /opt
sudo chmod -R 777 sonatype-work
  1. to start it from terminal manually, just enter nexus installation home/bin, then run command ./nexus run

In this case, we need to press ctrl+c keys to stop it.

  1. access it by :

http://localhost:8081

Make it as a service

In order to make it start automatically after server reboot, we need to make it as service.

It is a good practice to run that service as a specific user that has only required access rights rather than root user.

We can configure the repository manager to run as a service with init.d or systemd. Both are startup frameworks used in Linux-based systems such as Ubuntu and CentOS.

  • add linux user for nexus sudo vi /opt/nexus/bin/nexus.rc

make previous file looks like run_as_user="linux user"

  • create link sudo ln -s /opt/nexus/bin/nexus /etc/init.d/nexus

  • config init.d

cd /etc/init.d
sudo chkconfig --add nexus
sudo chkconfig --levels 345 nexus on
sudo service nexus start

The second command adds nexus as a service to be started and stopped with the command. chkconfig manages the symbolic links in /etc/rc[0-6].d which control the services to be started and stopped when the operating system restarts or transitions between run-levels. The third command adds nexus to run-levels 3, 4, and 5. Then the service command starts the repository manager.

Access it from other computers

sudo firewall-cmd --zone=public --permanent --add-service=http
sudo firewall-cmd --zone=public --add-port=8081/tcp --permanent
sudo firewall-cmd --reload
Read More

symbolic link and hard link

Symbolic link or called soft link, is a file which points to another file or directory, just like a pointer.

It does not contain data of target file, while hard link does.

Soft link is able to link to file/directory of remote computer and hard just link file on the same filesystem.

If we delete or move the target file, soft link becomes unusable, whereas hard link keeps the content of that file.

create soft link command:

[code]ln -s target_file soft_link_file[/code]

we can do operations on soft_link_file, e.g. cp, rm, just as we can do on target_file.

create hard link:

[code]ln target_file hard_link_file[/code]

Read More

centos 7 install svn server

  1. install httpd(apache)

    sudo yum install httpd

    Logs files are in /var/log/httpd

  2. install svn and apache module mod_dav_svn to make svn work with apache

    sudo yum install subversion mod_dav_svn

  3. modify svn configuration file

    sudo vi /etc/httpd/conf.modules.d/10-subversion.conf

    append the following content

    <Location /svn>
    DAV svn
    SVNParentPath /svn
    AuthName "SVN Repos"
    AuthType Basic
    AuthUserFile /etc/svn/svn-auth
    AuthzSVNAccessFile /svn/authz
    Require valid-user
    
    </Location>
      
    
    <Location> applies the enclosed directives only to matching URLs
    Syntax: <Location URL-path|URL> ... </Location>
    
    In the example below, requests to /private1, /private1/ and /private1/file.txt will have the enclosed directives applied,    but /private1other would not.
    
    <Location "/private1">
    # ...
    </Location>
    
    While for following example, requests to /private2/ and /private2/file.txt will have the enclosed directives applied, but    /private2 and /private2other would not.
    
    <Location "/private2/">
    # ...
    </Location>
    
    

    DAV svn

    Must be included in any Directory or Location block for a Subversion repository. It tells httpd to use the Subversion
    backend for mod_dav to handle all requests.

    SVNParentPath directory-path

    Specifies the location in the filesystem of a parent directory whose child directories are Subversion repositories. In a configuration block for a Subversion repository, either this directive or SVNPath must be present, but not both.

    SVNPath directory-path

    Specifies the location in the filesystem for a Subversion repository’s files. In a configuration block for a Subversion
    repository, either this directive or SVNParentPath must be present, but not both.

    AuthName is an arbitrary name that you choose for the authentication domain. Most browsers display this name in the
    dialog box when prompting for username and password.

    AuthType specifies the type of authentication to use.

    AuthUserFile specifies the location of the password file to use.

    AuthzSVNAccessFile specifies a file containing the permissions policy for paths within your repositories.

  4. create svn repo

    sudo mkdir /svn
    cd /svn
    sudo svnadmin create test
    sudo chown -R apache:apache test
    
  5. add svn user

    sudo mkdir /etc/svn
    sudo htpasswd -cm /etc/svn/svn-auth admin
    sudo chown root:apache /etc/svn/svn-auth
    sudo chmod 640 /etc/svn/svn-auth
    

    if you want to add second user

    sudo htpasswd -m /etc/svn/svn-auth user1

    remove c flag, just use -m from second user

  6. set permission for users

    sudo cp /svn/test/conf/authz /svn/authz
    
    sudo vi /svn/authz
    

    test is the repository name which created on step 4.

    In this file, add follwing content:

    [/]
    * = rw
    

    This means all user can read and write all repositories, this suit for most case.

    However, following config called path-based authorization which used to restrict the access to svn files. You need to ask yourself that do you really need it before using it or it’s just something that sounds good, because there are often invisible or visible costs associated with this feature.

    [groups]
    admin=admin
    repo1_user=user1,user2
    [/]
    @admin=rw
    
    [test:/]
    @repo1_user=rw
    

    In this file, [groups] is used to defined user group, e.g. repo1_user is group name, user1 is its user.

    [/] or [test:/] is svn repository path, its value can be [repos-name:path] or [path] when AuthzSVNAccessFile is
    used.

    If you configured per repository access files via AuthzSVNReposRelativeAccessFile directive, you should always use [path] form only.

    [repos-name:path] or [path] describe the permission of group or user for path, @admin=rw means admin is a group and it can read and write, while admin=r represents admin is a user and it only can read.

    If the user is not mentioned at all, no access is allowed.

    If you’re using the SVNParentPath directive, it’s important to specify the repository names in your sections. If you omit them, a section such as [/some/dir] will match the path /some/dir in every repository. If you’re using the SVNPath directive, however, it’s fine to provide only paths in your sections—after all, there’s only one repository.

  7. change selinux security context if selinux enabled

    403 forbidden will be thrown withoud next modification.

    sudo chcon -R -v –-type=httpd_sys_content_t /svn

  8. start appache

    sudo systemctl start httpd.service

    if you want apache start automatically when system boot, then we can use

    sudo systemctl enable httpd.service

  9. modify firewall such that other computers can access the svn

    sudo firewall-cmd --zone=public --permanent --add-service=http
    sudo firewall-cmd --reload
    

Finally, we can access svn from browser by http://svn/test.

Reference websites:

http://svnbook.red-bean.com/en/1.7/svn.ref.mod_dav_svn.conf.html
http://svnbook.red-bean.com/en/1.8/svn.serverconfig.pathbasedauthz.html
https://httpd.apache.org/docs/2.4/mod/core.html#location
http://svnbook.red-bean.com/en/1.7/svn.serverconfig.httpd.html
Read More

struts2 property tag show un-normal value

struts 2.0.9

The value is

AÜC

jsp

obj.value = "<s:property value='customer.name'/>"

obj represents an input field.

However, this input field value displayed as

[code]A& #xDC;C[/code]

AÜC is got from DB and it is correct in struts action.  Meanwhile if I just assign “AÜC” to obj.value in jsp, it also can show right string.

Therefore the problem is from .

I tried to add escapeHtml=’false’ to “<s:property value=’customer.name’ />”, but the jsp throws an exception and stop running.

Eventually,

I found that if we put

[code]<s:property value=’customer.name’ />[/code]

in element value attribute, e.g.

[code]<input value="<s:property value=’customer.name’ />" />[/code]

,

then it’s normal.

But if we use it in js, for example,

[code]

<script>

obj.value = "<s:property value=’customer.name’ />";

</script>

[/code]

then it will show in-normal value, in this case we need to use jstl

[code]

<script>

obj.value = ${customer.name}";

</script>

[/code]

Read More

SELinux brief

  • Security Enhanced Linux which is a mandatory access control(MAC) security mechanism which based on defined policies.  User can disable it.
  • As we know, users can control the permissions of files that they own by setting read, write and execute for specified user, group and others.  This is called discretionary access control(DAC). MAC and DAC make up the Linux security.  The flow is

screenshot-from-2016-11-27-23-07-23

  • SELinux has three modes: Enforcing is the default mode which will enable and enforce the SELinux security policy on the system, this will deny illegal access and log it. Permissive mode just log the actions without denying. Disabled mode means turn off the SELinux.  We can edit these modes by modifying /etc/sysconfig/selinux

Users may use the ‘sestatus’ command to view the current SELinux status:

$ sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: enforcing Mode from config file: enforcing Policy MLS status: enabled Policy deny_unknown status: allowed Max kernel policy version: 28
  • All processes and files have an SELinux security context which can be checked by ls -Z, e.g.
$ ls -Z drwxr-xr-x. frank frank unconfined_u:object_r:user_home_t:s0 Desktop unconfined_u:object_r:user_home_t:s0 is SELinux security context fields, unconfined_u means user, object_r represents role, user_home_t stands for (security context) type, s0 is mls which is not common used.
  • By default, SELinux log messages are written to /var/log/audit/audit.log via the Linux Auditing System audited.  If the audit daemon is not running, then messages are written to /var/log/messages.  SELinux log messages are labeled with the 'AVC' keyword

There are some reasons why SELinux deny access :

  • A mislabeled file
  • A process running under the wrong SELinux security context
  • A bug in policy . An application requires access to a file that wasn't anticipated when the policy was written and generate an error
  • An intrusion attempt

The first three we can deal with.

Take apache accessing /svn/authz for example,

ps axZ | grep httpd system_u:system_r:httpd_t:s0 5166 ? Ss 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5181 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5182 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5183 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5184 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5185 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5350 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5351 ? S 0:00 /usr/sbin/httpd -DFOREGROUND system_u:system_r:httpd_t:s0 5352 ? S 0:00 /usr/sbin/httpd -DFOREGROUND unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 5362 pts/0 S+ 0:00 grep --color=auto httpd

httpd_t is the selinux type of httpd.

cd /svn ls -Z -rw-r--r--. root root unconfined_u:object_r:default_t:s0 authz

default_t is the type of /svn/authz file.

For SELinux, access is only allowed between similar types, so apache running as httpd can access type httpd_sys_content,  but  cannot read /svn/authz because the directory and file(s) have wrong security context even though user give 777 permission for it via DAC.

In order to let apache access this file, we need to set correct security context type ‘httpd_sys_content_t’ by following command:

sudo chcon -Rv --type=httpd_sys_content_t /svn

-R means recursive.

Read More

install centos 7 with windows 7

  1. For my laptop, I need to change UEFI to Legacy in BIOS setup such that it is able to use usb bootable to install OS.
  2. Create usb bootable with the help of Rufus
  3. Install windows 7
  4. Install cent os 7
  5. In step 'Installation Destination', choose hard drive and 'I will configure partitioning'

select-date-and-time-601x450 centos-dual-device-selection

  1. Manual partitioning page looks like next. We can see that there is ‘Unknown’ tab, this tab shows the windows partitions(This screen shot is from web and it displays existing linux partitions.).

In my case, the windows 7 has three drivers C, D and E. Wherein E is empty. So I

  • select E and click the button ‘-’, marked 2 in picture, this will free this partition space.
  • click button ‘+’, marked 3 in following diagram, this is used to create Cent OS partition. Create /, /boot, swap and /biosboot separately in pop up dialog
  • Finally, click the ‘Done’ button and confirm the change dialog

select-partitioning-scheme

  1. Configure the ‘Network and Hostname’ like step 5 diagram
  2. Continue until install successful
  3. Install gnome desktop environment
  • sudo yum groups install "GNOME Desktop"
  • sudo systemctl set-default graphical.target
  1. Add windows boot item
  • sudo grub2-mkconfig > /dev/null, it is used to check windows detected or not
  • if windows can be found in previous step, run : sudo grub2-mkconfig -o /boot/grub2/grub.cfg

reboot the system.

Note : the diagrams in this article are from web.

Read More

javascript regular expression

In js, there is a function “replace(source, target)” which means replace the source of original with target.

Wherein source can be a plain string or regular expression, e.g.

var s = " You can click this link to access detail : ${url=http://192.168.0.1/TEST/a?} "; var t = s.replace(/\${url=([^+]+)}/,"");

if source is regular expression :

  • it CANNOT be enclosed by ""
  • regular expression has to be start with / and end with /, while /.../g represents replace all match string
  • $ needs to be escaped, while { or } doesn't
Read More

Git basic

1.What is Git

Git is the distributed version control system. Git is responsible for keeping track of changes to

content (usually source code files), and it provides mechanisms for sharing that content with others.

2.Git Hub

GitHub is a company that provides Git repository hosting.

3.Git installation

4.Eclipse Git

  • JGit is the Java implementation of Git. It is a library, that also can be used in your own applications. It also provides some sort of CLI operations.
  • EGit on the other side is the Eclipse team provider plugin for Git, which uses JGit as Git implementation. Simplified you could say EGit is the UI part, and JGit the background part. JGit doesn't depend on EGit, but EGit does depend on JGit.

5.Files in Git

files in git : tracked, untracked and ignored.

ignored files are tracked in a special file name .gitignore (can be for specify repository

or all repositories by git config) that is checked in at the root of your repository.

There is no explicit git ignore command, instead the .gitignore file must be edited and

committed by hand when you have new files that you wish to ignore.

.gitnore files contain patterns that are matched against file names in your repository to determine

whether or not they should be ignored.

6.Git flow

git_basic_1

7.How to contribute to other people’s project

When we work with another user’s public repository, typically we have read access to the code but not write access. In order to change their code, we have to create pull request. The flow is :

git_basic_2

Read More

maven use specified jdk

Currently, maven uses jdk 1.5 by default, that is even we specify JDK and compiler in eclipse, if we check out/create maven project, or update maven project or clean install, it will use jdk 1.5 rather than eclipse settings.   This is not convenient and has error sometimes if we use higher jdk.

In order to use specified jdk, we can add following to maven settings.xml such that it uses jdk 1.7:

<profile>
<id>jdk-1.7</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.7</jdk>
</activation>
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.compilerVersion>1.7</maven.compiler.compilerVersion>
</properties>
</profile>
Read More

JSTL

1.What

JSTL(JSP Standard Tag Library) is a collection of useful jsp tags which to handle jsp applications.

<c:xxx> tags to control the flow in the jsp page.

<fmt:xxx> tags for date/number formatting and i18n.

<sql:xxx> tags for sql operation

<x:xxx> for handling xml

${fn:xxx()} are some utility EL functions.

2.How

JSTL is part of the Java EE API and included in Java EE application servers like TomEE, Glassfish, but not in servelet containers such as Tomcat, Jetty.

Read More

mybatis transaction

Mybatis only

Developers need to call commit() explicitly such that changes can be stored in DB.  While for rollback(), we don’t have to call it in most of the time as mybatis will do that for us if we don’t call commit.

However if we need more fine grained control over a session where multiple commits and rollbacks are possible, we are able to use rollback.

Mybatis and spring integration

Mybatis-spring allows mybatis to participate in spring transactions.

In this case, there is no need to call commit or rollback explicitly and UnsupportedOperationException will thrown if we do that.

In order to use spring transaction, the additional changes as follows :

  • add annotation @Transactional on the method which be used in transaction
  • spring config file looks like

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
           xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
    <property name="jndiName" value="java:/comp/env/jdbc/example" /> 
    </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
    <property name="configLocation" value="classpath:mybatis-config.xml" /> 
    <property name="dataSource" ref="dataSource" /> 
    </bean>
    
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> 
    <constructor-arg index="0" ref="sqlSessionFactory" /> 
    </bean>
    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource" /> 
    </bean>
    
    </beans>
    
Read More

Batch processing in DB

What

Group sql statements into a batch and submit them with one call to DB, rather than send each statement one by one, this is batch processing.

Why

Batch processing can reduce the amount of communication overhead, thereby improving  performance.

It is faster than sending them one by one without waiting for each one to finish, and the DB may be execute some of them in parallel.

How

In mybatis, we have two approaches to implement batch processing:

  1. if integrate mybatis and spring

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
       <constructor-arg index="0" ref="sqlSessionFactory" />
    
       <constructor-arg index="1" value="BATCH" />
    
    </bean>
    

    then in code :

    for() {
    
       sqlSession.update();
    
    }
    
  2. without spring

    SqlSession session = factory.openSession(ExecutorType.BATCH);			
    for(Child c : childs) {
    
      session.update("updateChild", c);
    
    }
    
    session.commit();
    
Read More

Spring Struts2 Mybatis Integration

Configure the spring listener and struts2 filter in web.xml

<context-param>

<param-name>contextConfigLocation</param-name>

<!-- the applicationContext.xml should be placed under WEN-INF by default. However we can use <context-param> to declare it is in src/main/resource with classpath:applicationContext.xml-->

<param-value>classpath:applicationContext.xml</param-value>

</context-param>

<listener>

<!-- Following listener is used to load the spring context file. -->

<listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<filter>

<filter-name>struts2</filter-name>

<!-- struts2 filter class path may be differ in different version-->

<filter-class>

org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter

</filter-class>

</filter>

<filter-mapping>

<filter-name>struts2</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

define struts2 action bean, data source and mybatis sql session in applicationContext.xml

<bean id="helloworld" class="example.my.integration.struts.HelloWorld">

<!-- add sqlSession in action class in this case, because we will query db from action class directly with the help of sqlSession -->

<property name="sqlSession" ref="sqlSession" />

</bean>

<bean id="dataSource"

class="org.springframework.jndi.JndiObjectFactoryBean">

<!-- Using JndiObjectFactoryBean such that we can define db resource in tomcat context.xml without configuring in project. Meanwhile we don't need to use any code to do lookup jndi or connect db, just use mybatis sqlSession api to operate db-->

<property name="jndiName" value="java:/comp/env/jdbc/example" />

</bean>

<!-- integrate spring with mybatis by using following two beans -->

<bean id="sqlSessionFactory"

class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="configLocation" value="classpath:mybatis-config.xml" />

<property name="dataSource" ref="dataSource" />

</bean>

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">

<constructor-arg index="0" ref="sqlSessionFactory" />

</bean>

In struts.xml, the value of action class should be bean id which declared in applicationContext.xml

add struts2-spring-plugin, mybatis-spring jars in pom.xml

Read More

connection pool

What is connection pool

When application needs to operate the database, it has to create a connection and close it after finishing.

This is costly and waste resources as well as affect the performance for each user/request.

Therefore, this is why connection pool comes. It is a cache of database connection so that connection can be reused.

Connection is placed in the pool after it is created or the operation finished. It is used again so that a new connection does not have to be established.

Generally, the pool has min/initial and max connection, if it reaches the initial number, then a new connection will be created and placed in pool. While it reaches max number, then new operations has to wait current operation release the connection.

Products

There are some connection pool products, such as c3p0, DBCP.

How to use

Take c3p0 with spring and mybatis for example.

The context.xml of tomcat looks like next :

  <Resource name="jdbc/test" auth="Container"
  type="com.mchange.v2.c3p0.ComboPooledDataSource"
  factory="org.apache.naming.factory.BeanFactory"
  user="test"
  password=""
  jdbcUrl="jdbc:mysql://localhost:3306/test"
  driverClass="com.mysql.jdbc.Driver"
  minPoolSize="2"
  initialPoolSize="3"
  maxPoolSize="10" />

Spring config file is :

  <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:/comp/env/jdbc/test" />
  </bean>

  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="configLocation" value="classpath:config/mybatis-config.xml" />
    <property name="dataSource" ref="dataSource" />
  </bean>
  
  <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory" />
  </bean>
Read More

Sql injection

1.What is sql injection

Take following code for example,

   Statement st = conn.createStatement(); String query = "select * from table where userName='" + user + "'"; st.executeQuery(query);

For above code, if value of user is : a’ or ‘1’ = ‘1, then the sql will be : select * from table         where userName=’a’ or ‘1’=’1’, as we know, this where clause always return true,  this is      sql  injection.

2.How to prevent it in Java

We can use PreparedStatement with placeholder to solve this problem, the code looks            like :

 PreparedStatement pstmt = con.prepareStatement("select * from table where userName=?"); pstmt.setString(1,user);

the setXX method do all the validation and escaping the special character.

Now, if user still input value : a’ or ‘1’ = ‘1, the sql is : select * from table where                       userName=’a\, or '1'='1’

When we use ORM tool like mybatis, it uses PreparedStatement if #{} be used in sql.

However, ${} is interpreted as string substitution, hence it has risk of sql injection.

Read More

struts interceptor

what is interceptor

Interceptor is used for doing additional handling before/after calling action method.

config struts.xml

there are two ways to define interceptors :

Method 1

<interceptors> 
 <interceptor name="first" class="example.my.interceptor.MyInterceptor" />                
 <interceptor name="second"        class="example.my.interceptor.AnotherInterceptor" /> 
</interceptors>
<action name="empinfo" class="example.my.i18n.EmpInfo" method="execute"> 
 <result name="input">/index.jsp</result> 
 <interceptor-ref name="timer" /> 
 <interceptor-ref name="first" /> 
 <interceptor-ref name="second" /> 
</action>

wherein, ‘timer’ is built-in interceptor which is used for recording the execution time for action method, so there is no need to declare it in <interceptors>

For custom interceptors, we are supposed to declare in <interceptors>

Method 2

<interceptors> 
 <interceptor name="first" class="example.my.interceptor.MyInterceptor" /> 
 <interceptor name="second" class="example.my.interceptor.AnotherInterceptor" /> 
 <interceptor-stack name="myStack">     
 <interceptor-ref name="second" />     
 <interceptor-ref name="first" /> 
 </interceptor-stack> 
</interceptors>
<action name="empinfo" class="example.my.i18n.EmpInfo" method="execute"> 
 <result name="success">/success.jsp</result> 
 <interceptor-ref name="myStack" /> 
</action>

create custom interceptors

custom interceptor has to extend AbstractInterceptor or implement Interceptor :

public class MyInterceptor extends AbstractInterceptor{
private static final long serialVersionUID = -3169055473033684813L;

@Override 
public String intercept(ActionInvocation invocation) throws Exception { 
System.out.println(" MyInterceptor pre-processing before calling execute()");

invocation.invoke();

System.out.println("MyInterceptor post-process after calling execute()"); 
return null; }

}
public class AnotherInterceptor implements Interceptor{
private static final long serialVersionUID = 1761916853142898972L;

@Override public void destroy() { }

@Override public void init() { }

@Override public String intercept(ActionInvocation invocation) throws Exception { 
System.out.println(" AnotherInterceptor pre-processing before calling execute()");

invocation.invoke();

System.out.println("AnotherInterceptor post-process after calling execute()"); 
return null; }

}

the invocation.invoke() will call other interceptor or actual action method.

The order of interceptor calling is the same as order of interceptor definition, take 2.1 for example, the output is :

MyInterceptor pre-processing before calling execute()
AnotherInterceptor pre-processing before calling execute()

action method is exectuting !
AnotherInterceptor post-process after calling execute()
MyInterceptor post-process after calling execute()
Read More

struts i18n

Struts2 I18n

Internationalization(aka I18n) is done via message resource(also called resource bundle) and locale.

Message Resource

Message resource is a properties file which looks like next:

personBean.firstName=Nombre
personBean.lastName=Apellidos
thankyou=Gracias por registrarse, %{personBean.firstName}. 

In struts2, this file has three level:

  1. Class Level

    The name of properties file has to be same as struts action class as well as the package.

    For example, there is action src/main/java/example/struts2/Login.java, then the properties file should be src/main/resources/example/struts2/Login.properties

    This rule is suited for interface too.

  2. Package Level

    properties file name is package.properties, cannot be other names.

    For instance, package.properties placed under src/main/resources/example/struts, then all class under package
    example.struts or its sub-packages can use this resource file.

  3. Global Level

    For this level, developer need to declare the global properties file in struts.xml like , the file name can be any value without extension.

Search Order

The search order is : 1 -> 2 -> 3.

For example, there is example.struts2.i18n.Login.Java, the order is: Search Login.properties under the example.struts2.i18n, if there is not, then search the package.properties under the example.struts2.i18n, if not, search package.properties under the example.struts2, etc.

Usage

The framework supports message resource in the following places:

  • the UI tags <s:textfield key="properties-file-key-name" /> <s:text name="properties-file-key-name" /> <s:property value="getText('some.key')" /> <s:i18n name="example.struts.i18n.p"></s:i18n><s:text name="user.name" /></s:i18n> it ask for user.name message from example/struts/i18n/p.properties
  • messages and errors from the ValidationAware
  • within action class through the getText() method

    public void validate(){
          if("".equals(getUsername())){
               addFieldError("username", getText("username.required"));
          }
    		
     }
    

Using only global bundle

If you don’t need to use the package-scan-functionality and only base on the global bundles (those provided by the framework and via struts.custom.i18n.resources) you can use existing GlobalLocalizedTextProvider implementation. To use this please define the following option in your struts.xml:

<constant name="struts.localizedTextProvider" value="global-only" />

Custom TextProvider and TextProviderFactory

If you want use a different logic to search for localized messages, or you want to use a database or just want to
search default bundles, you must implement both those interfaces (or subclass the existing implementations). You can check a small example app how to use both. Please remember that the TextProvider interface is implemented by the ActionSupport class, that’s why an extra layer - TextProviderFactory - is needed.

Locale

By default, struts2 uses the user’s default locale.
The convention of properties file name is File-name_locale-code.properties, such as A_zh-CN.properties. If locale is en for English then locale code can be ignored.

Set locale value

Developer is able to set locale value by parameter request_locale.

```Java Server Pages

zh-CN

Change language to chinese simplified

```

By specifying the locale as a url parameter, it tells struts to look for property files ends with zh-CN.

I18n Interceptor

Following is the info from struts official doc about the I18n Interceptor:

An interceptor that handles setting the locale specified in a session as the locale for the current action request. In addition, this interceptor will look for a specific HTTP request parameter and set the locale to whatever value is
provided, it also looks for specific cookie to read locale from. This means that this interceptor can be used to allow for your application to dynamically change the locale for the
user’s session or, alternatively, only for the current request. This is very useful for applications that require multi-lingual support and want the user to be able to set his or her language preference at any point. The locale parameter is removed during the execution of this interceptor, ensuring that properties aren’t set on an action (such as request_locale) that have no typical corresponding setter in your action. For example, using the default parameter name, a request to foo.action?request_locale=en_US, then the locale for US
English is saved in the user’s session and will be used for all future requests. If there is no locale set (for example with the first visit), the interceptor uses the browser locale. Parameters parameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to and save in the session. By default this is request_locale requestCookieParameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to and save in a cookie. By default this is request_cookie_locale requestOnlyParameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to for the current request only, without saving it in the session. By default this is request_only_locale attributeName (optional) - the name of the session key to store the selected locale. By default this is
WW_TRANS_I18N_LOCALE localeStorage (optional) - the name of storage location, it can be none, session or cookie. By default this is session Examples <interceptor name="i18nCookie" class="org.apache.struts2.interceptor.I18nInterceptor"/> <action name="someAction" class="com.examples.SomeAction"> <interceptor-ref name="i18nCookie"> <param name="localeStorage">cookie</param> </interceptor-ref> <interceptor-ref name="basicStack"/> <result name="success">good_result.ftl</result> </action>

## Front-end I18n

There is also front-end I18n, like Jquery I18n

I18n at database level

There is a good article about the i18n in DB, please refer it for detail.

Read More

struts2 helloworld

struts version is 2.3.28

1.project structure

create a dynamic web project in Eclipse, then convert it to maven project and add sturts-core 2.3.28 dependency. the final project explorer looks like next :

struts2-helloworld.PNG

2.View page

2.1.index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>;
<%-- the taglib directive tells the Servlet container that this page will be using the struts2 tags and that these tags will be preceded by s.--%>
<%@ taglib prefix="s" uri="/struts-tags" >
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h1>Hello World from Struts2</h1>
<!-- if we want to use DMI, then the action name can be hello!nonExecute.action or hello!nonExecute here--&gt;
<form action="hello">
Please enter your name :<br>
<input type="text" name="name" />
<input type="submit" value="say hello" />
</form>
</body>
</html>

DMI(dynamic method invocation) means run non-execute method of action class, the above form action represents it will run execute() of action class. However, if action name is hello.nonExecute, then it runs nonExecute() of action class.

2.2.result page

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<!-- the s:property tag displays the value of action class property 'name' which is returned by the method getName() of HelloWorldAction -->
Struts2 Hello World, <s:property value="name" />
</body>
</html>

3.action class

public class HelloWorldAction {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String execute() {

return "success";
}

public String nonExecute() {

return "fail";
}

}

4.config files

4.1.struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- next statement is required otherwise there is error when start tomcat -->
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- set constant struts.devMode to true such that we can see some useful log messages -->
<constant name="struts.devMode" value="true" />
<!-- In struts2 2.3.28, DynamicMethodInvocation must be set to true explicitly if we want to use DMI -->
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="helloworld" extends="struts-default">
<!-- property 'method' of action tag means executing which method of action class, default is execute() -->
<action name="hello" class="cn.my.example.HelloWorldAction"
>
<result name="success">/HelloWorld.jsp</result>
<!-- if invoked method return success then we take the user to HelloWorld.jsp -->
<result name="fail">/error.jsp</result>
</action>
</package>
</struts>

Note : 

  1. <constant name="struts.enable.DynamicMethodInvocation" value="true" /> has to be declared in struts.xml in order to use DMI.
  2. For <action name="" class="">, the class value is qualified name, that is class="cn.my.example.HelloWorld". While if struts is integrated with spring, its value is the id value of <bean id=""> which defined in spring applicationContext.xml

4.2.web.xml

<filter>
<filter-name>struts2</filter-name>
<!-- <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> -->
<!-- for struts2 2.3.28, the filter is next instead of above -->
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Read More

oracle sql tuning examples

1.

there is one sql as follows :

select /*+index(create_time) */ * from h where h.result='F' and h.code<>'DO' and (h.code like :1 or h.code like :2 or h.code like :3) and h.create_time>:4 and h.create_time<:5

it has index on column ‘create_time’, :1, :2 and :3 can be %A,A% or %A%.

DBA told us that this is top sql, hence we need to optimize it.

My analysis are :

  • it is useless that we create index on column 'code' since its value could be %A
  • result only can be 'S' or 'F', but the 'S' occupy most data in DB(about 99%)
  • 'create_time' index is not good according to execute plan

Therefore, after removing hint and add index on column ‘result’, the efficient improved huge.

 

Read More

Spring MVC Hello World

This is a hello world example with spring boot 2.

Flow

_config.yml

Example

This is a very simple example, when user open it in the browser, index.jsp will be shown and user can click some buttons to fetch data from controller.

Maven POM


		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
    		<groupId>org.apache.tomcat.embed</groupId>
    		<artifactId>tomcat-embed-jasper</artifactId>
    		<scope>provided</scope>
		</dependency>

**Note: tomcat-embed-jasper is used to compile jsp files in embeded tomcat. If it is ommitted, then jsp cannot be shown when you access it if you use embed tomcat. After adding this dependency, you have to restart your spring boot app manually. **

jsp file

index.jsp is placed under src/main/webapp.

<!DOCTYPE html>
<html>
<head>
    <title>Hello SpringMVC</title>
    <script src="jquery-3.3.1.min.js"></script>
</head>
<body>
<input type="button" value="post json" onclick="getUser()" />
<input type="button" value="get user 2" onclick="getUser2()" />
<input type="button" value="get user 3" onclick="getUser3()" />
<script>
function getUser() {
	

	   var search = {
	      "userId" : 2
	   }
	   
	   jQuery.ajax({
	      type: "POST",
	      contentType : 'application/json; charset=utf-8',
	      dataType : 'json',
	      url: "/sbw/user/getUser",
	      data: JSON.stringify(search), 
	      success :function(result) {console.log(result);
	       alert(result.userName);
	     }
	  });
}

function getUser2() {
	

	   var search = {
	      "userId" : 2
	   }
	   //both post and get are ok
	   jQuery.ajax({
	      type: "GET",	  	     
	      url: "/sbw/user/getUser2",
	      data: search, 
	      success :function(result) {console.log(result);
	       alert(result.userName);
	     }
	  });
}

function getUser3() {
	

	   var search = {
	      "userId" : 2
	   }
	   
	 //both post and get are ok
	   jQuery.ajax({
	      type: "POST",	  	     
	      url: "/sbw/user/getUser3",
	      data: search, 
	      success :function(result) {console.log(result);
	       alert(result.userName);
	     }
	  });
}
</script>
</body>
</html>

When you open website in browser by url ‘http://localhost:8080/sbw, the index.jsp or index.html will be lookuped under the root path or the path defined in spring.mvc.view.prefix. Alternatively, you can access index.jsp by 'http://localhost:8080/sbw.

WEB-INF

It’s a good practice to place resources like jsp under the WEB-INF folder such that user cannot access them directly from the browser by typing the url.

The Servlet 2.4 specification says this about WEB-INF:

A special directory exists within the application hierarchy named WEB-INF. This directory contains all things related to the application that aren’t in the document root of the application. The WEB-INF node is not part of the public document tree of the application. No file contained in the WEB-INF directory may be served directly to a client by the container. However, the contents of the WEB-INF directory are visible to servlet code using the getResource and getResourceAsStream method calls on the ServletContext, and may be exposed using the RequestDispatcher calls.

The change in Servlet 3.0 & 3.1 (JSR 340) allows serving static resources and JSPs from within a JAR stored in WEB-INF/lib.

Except for static resources and JSPs packaged in the META- INF/resources of a JAR file that resides in the WEB-INF/lib directory, no other files contained in the WEB-INF directory may be served directly to a client by the container.

Thus from Servlet 3.0, static files can be served from: WAR file > WEB-INF > lib > JAR file > META-INF > resources > yourStaticFilesGoHere

Application yml

server:
  servlet:
    context-path: /sbw
  
spring:
  mvc:
    view:
      prefix: /
      suffix: .jsp
  datasource: 
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 123456  
    
mybatis:
  type-aliases-package: com.example.sb.model
  mapper-locations: classpath:sql/*.xml
  configuration:
    map-underscore-to-camel-case: true        
        
logging.level:
  root: info
  java.sql.PreparedStatement: debug
  com.example.sb.dao: debug

Controller

@RestController
@RequestMapping("/user/")
public class UserAction {

	@Autowired
	private UserService userService;  
	
	@RequestMapping(value = "getUser")
	public User getuser(@RequestBody User user) {
		
		return this.userService.getUser(user.getUserId());
	}	
	
	@RequestMapping(value = "getUser2")
	public User getUser2(User user) {
	
		return this.userService.getUser(user.getUserId());
	}
	
	//@RequestParam cannot be ommited in this case
	@RequestMapping(value = "getUser3")
	public User getUser3(@RequestParam Map<String,Object> map) {
	
		return this.userService.getUser(Integer.valueOf(map.get("userId").toString()));
	}

}

@RequestMapping

It can be applied to the controller class as well as methods.

It is used to map web requests onto specific handler classe and/or handler method.

You can define the request method like @RequestMapping(value="/getUser", method=RequestMethod.POST).

If you do not specify any mapping this method will resolve all the http request, i.e. you can send GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE request to the specified url and it will be resolved.

produces and consumes

The RequestMapping has attributes produces and consumes, e.g. @RequestMapping(value = "getBooking", produces = {MediaType.APPLICATION_JSON_VALUE})

The produces specify the data format that will be returned to client.

produces = {MediaType.APPLICATION_JSON_VALUE} means produce a response with content-type=application/json.

@RequestParam

Indicating that a method parameter should be bound to a web request parameter. For example,

http://localhost:8080/sbw/user/getUser?userId=2

In the above URL request, the values for userId can be accessed as below:

  public User getUser( @RequestParam(value="userId") String userId ){
   ...
  }

If you’re sending your data as classic request params, you can bind to object by simply omitting the @RequestParam, e.g.

  @RequestMapping(value = "getUser2")
	public User getUser2(User user) {
	
		return this.userService.getUser(user.getUserId());
	}
  function getUser2() {
	

	   var search = {
	      "userId" : 2
	   }
	  
	   jQuery.ajax({
	      type: "GET",	  	     
	      url: "/sbw/user/getUser2",
	      data: search, 
	      success :function(result) {
        //....
	     }
	  });
  }

@PathVariable

@PathVariable is similar as @RequestParam except that it is used for accessing the values from the URI template.

http://localhost:8080/sbw/getUser/2?userName=fk

  @RequestMapping("/getUser/{userId}")
	public String getUser(@PathVariable(value="userId") int userId,
	@RequestParam(value="userName") String userName,
	){
     .......
  }

@RestController

@RestController is @Controller + @ResponseBody, and it avoids the need of prefixing every method with @ResponseBody.

The RESTful web service controller simply returns the object and the object data is written directly to the HTTP response as JSON/XML automatically.

Spring lets you return data directly from the controller, without looking for a view, using the @ResponseBody annotation on a method.

@Requestbody & @ResponseBody annotations are used to convert the body of the HTTP request to POJO or POJO to response body.

Both these annotations will use registered HTTP message converters in the process of converting/mapping HTTP request/response body with POJO.

For example, If you’re sending json in http request and a POJO is used as controller method parameter, then you have to use @RequestBody such that the json can be converted into this POJO.

return json

Every String will treated as a string and every other Object will get serialised/deserialised by Jackson.

This allows to serialise manually (by returning String) or automatically (by returning something else) in Spring controllers.

  @RestController
  @RequestMapping(value = "/booking/")
  public class BookingAction {
  
    @RequestMapping("getBooking")
    public Booking getBooking() {
        //get booking data
	return booking;
    }
  }

Spring boot default use jackson, this class is annotated with @RestController, and this method returns booking which is a POJO, therefore, this POJO will be converted into json.

However, if it is :

   @RequestMapping("getBooking")
    public String getBooking() {
        //get booking data
	return JSONObject.fromObject(booking).toString();
    }  

It returns json data as raw string not POJO, and if the client didn’t specify an Accept header, then Spring won’t feel need to do anything with the result just return string, that is the return value will be handled by StringHttpMessageConverter which sets the Content-type header to text/plain.

In this case, there are 2 approaches to return a JSON string:

  1. In the client, set Accept header value as application/json
  2. add produces to @RequestMapping(value = "getBooking", produces = {MediaType.APPLICATION_JSON_VALUE})
HTTP Message Converter

Spring has a list of HttpMessageConverters registered in the background.

Spring loops through all registered HTTPMessageConverters seeking the first that fits the given mime type and class, and then uses it for the actual conversion.

From springbootdev:

The client (web browser or REST client) cannot send the java objects (as it is) in the body of the HTTP request. On the other hand, the server application cannot compose the body of the HTTP response with java objects (as it is).
Simply the HTTP Request and Response body cannot contains the in the form of java objects.

HTTP request and response body should contain either JSON , XML or some other type of formatted data (RSS etc).
Therefore the HTTP message converters are used to convert the HTTP request body (either in JSON or XML) to the Java objects and Java objects back to XML or JSON for embedding into the HTTP response body.

The spring mvc will check the header of http request to pick a appropriate message converter:

  • Content-Type, if the Content-Type is application/json, then it will select a JSON to POJO converter.
  • Accept, if the Accept is application/json , then it will select a POJO to JSON converter.

@ModelAttribute

@ModelAttribute is used to bind a method parameter or a method return value to a named model attribute. It can be used either on methods or on method parameters.

Spring invokes all methods that have @ModelAttribute annotation before handler methods (i.e. methods annotated with the @RequestMapping) in a same controller.

Spring MVC VS Struts2

  1. Struts 2 is simplier and straight forward, while we need to take more efforts to master spring mvc
  2. spring mvc use DispatcherServlet which is a servlet, while struts 2 use StrutsPrepareAndExecuteFilter which is filter
  3. Struts 2 action is initiated every time when a request is made, whereas in Spring MVC the controller is singleton
  4. Spring MVC is deeply integreated in Spring, Struts 2 is not
  5. Struts 2 couples validation and action, spring mvc decouple validation from controller
Read More

mybatis hello world

mybatis : 3.3.1

jdk     : 1.7

mysql   : 5.6

In this example, the steps as follows :

  • define mybatis configuration xml file
  • create POJO class which standing for table columns
  • generate mapper interface which representing the operations for table, e.g. insert, for annotation usage, developer should write sql statement in mapper interface, while for xml, mapper xml configuration file needed to be created which containing sql  statements.

Mybatis configuration xml file

<?xml version="1.0" encoding="UTF-8" ?>

<!-- doctype is required and has to the same as following for configuration file -->

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<!-- The elements under configuration has order, e.g. if we change the order

of settings and typeAliases, then there is error tip.

-->

<settings>

<setting name="logImpl" value="SLF4J" />

</settings>

<!-- use Address to represent cn.example.mybatis.model.Address. via typeAlias-->

<typeAliases>

<typeAlias alias="Address" type="cn.example.mybatis.model.Address" />

</typeAliases>

<environments default="development">

<environment id="development">

<transactionManager type="JDBC" />

<dataSource type="POOLED">

<property name="driver" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql://localhost:3306/test" />

<property name="username" value="root" />

<property name="password" value="" />

</dataSource>

</environment>

</environments>

<mappers>

<!-- resource for xml approach and class for annotation -->

<!-- <mapper resource="AddressMapper.xml" /> -->

<mapper class="cn.example.mybatis.annotation.AuthorMapper" />

</mappers>

</configuration>

POJO class

general pojo class

mapper interface

public interface AddressMapper {

public void insertAddress(String zipCode);

public List<Address> getAddressByIdList();

public Address getAddress(@Param("id") int id,

@Param("zipCode") String zipCode);

public void updateAddress();

public void updateAddressById(Address a);

public void deleteAddressById(int id);

public void insertAddress(Address a);

}

with mapper configuration xml file :

<?xml version="1.0" encoding="UTF-8" ?>

<!-- doctype is required and has to the same as following for mapper file -->

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- The value of namesapce should be with package name -->

<mapper namespace="cn.example.mybatis.xml.AddressMapper">

<!-- resultType still is 'Address' even it returns a list -->

<select id="getAddressByIdList" resultType="Address">

select * from address;

</select>

<!-- multiple parameters should be use parameterType="map" -->

<select id="getAddress" parameterType="map" resultType="Address">

select * from address where id=#{id} and zipCode=#{zipCode};

</select>

<!-- parameterType is optional in this case -->

<update id="updateAddressById" parameterType="Address">

update address set zipCode=#{zipCode} where id=#{id}

</update>

<delete id="deleteAddressById">

delete from address where id=#{id}

</delete>

<!-- the 'id' of address is auto increment in DB, but developer don't need to care its value when executing insert statement, the sql just as follows. -->

<insert id="insertAddress" parameterType="Address">

insert into address(zipCode) values(#{zipCode});

</insert>

</mapper>

**Note:

  1. parameterType is optional, resultType is required. e.g. select * from student where id = #{id} and name = #{name}, you can pass a map which contains keys ‘id’ and ‘name’, or you can pass student java bean which has id and name fields
  2. In dynamic sql, developer can use <if>, like : select * from student where <if test="id != null ">id = #{id}</if> <if test="name != null"> and name = #{name} </if> However if id and name are null, then this sql be select * from student where or if id is null but name is not null, then sql is select * from student where and name = ? bothe are wrong. The solution is change sql to : select * from student <where> <if test="id != null ">id = #{id}</if><if test="name != null"> and name=#{name}</if> </where> With the help of <where>, if id and name are null, then the sql be select * from student or if id is null but name is not null, then sql is select * from student where name = ?, mybatis will strip and off from and name = #{name}
  3. <foreach collection="list" item="i">#{i.id}</foreach>, item is required, and if collection stands for list of custom POJO, then #{i.id} has to be used, if this list means List etc, then `#{id}` is ok **

or for annotation without mapper configuration:

public interface AuthorMapper {

@Select("select * from author where id=#{id} and name=#{name}")

public Author getAuthor(@Param("id") int id,@Param("name") String name);

@Select("select * from author")

public List<Author> getAuthors();

@Insert("insert into author(name) values(#{name})")

public void insertAuthor(Author a);

@Update("update author set name=#{name} where id=#{id}")

public void updateAuthor(Author a);

@Delete("delete from author where id=#{id}")

public void deleteAuthor(int id);

}

Test Class

InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

SqlSession session = factory.openSession();

AuthorMapper mapper = session.getMapper(AuthorMapper.class);

mapper.deleteAuthor(10);

session.commit();

Use sql of another xml file

For instance, there are two sql xml files sql1.xml and sql2.xml

<mapper namespace="sql1">
    
    <select id="select1" resultType="student">
	....
    </select>
</mapper>
<mapper namespace="sql2">
    
    <select id="select2" resultType="student">
	....
    </select>
</mapper>

If developer want to use select1 in sql2.xml, then he/she just use qualified name of select1, that is sql1.select1

Read More

java web service

1.What is web service

    It is used to communicate from one system to another system over the internet even they are build in different programming language.

2.Types of web service

  • soap(simple object access protocol) is xml based and the java-ws(java api for xml web service) is its API.

  • restful(representational state transfer) is an architectural style not a protocol and jax-rs(java api for restful web service) is its API.

web service api

Read More

sql group by

1.group by

The group by statement is used to group the result-set by one or more columns, e.g.

group_by

if the sql is : select rate_type, effective_date from table group by rate_type, effective_date, then the result looks like next :

SC    02/10/15

SC    12/08/16

Note : the columns in select have to be in group by or in aggregate functions, in other words, if we want to select rate_type, effective_date, approve_time in a sql with group by, then the sql should be :

‘select rate_type, effective_date, approve_time from table group by rate_type,effective_date,approve_time’

or

‘select rate_type, effective_code, max(approve_time) from table group by rate_type,effective_date’

Note : the column with varchar type also can be used in aggregate functions besides the number

and it is wrong if it is ‘select rate_type, effective_date, approve_time from table group by rate_type,effective_date’.

2.having

The having clause is used with group by usually and the aggregate functions following it.

It was added to sql because where clause could not be used with aggregate functions.

Read More

sql join

Left join

_config.yml

The result set of left join is : Carterisan product of meet the join conditions of table A and table B + rest of table A

Inner join

_config.yml

The result set of inner join only is the Carterisan product of meet the join conditions of table A and table B

Read More