jQuery Masonry : http://masonry.desandro.com/index.html
If call ajax and render each elements dynamically by javascrit, need to call 'appended' method. but sometimes the elements only to be shown on single column.
if need to show elements with multiple columns,
set width first
$("#div").masonry({columnWidth: 310});
var box = renderSingleElement(item);
var $singlebox = $(box);
$("#div_single_element").append($singlebox).masonry( 'appended', $singlebox);
take note if set column width as 310, the width of single element should not be greater than 285, otherwise the elements still be in one column, not multiple columns, so take care to set the element width and column width.
Thursday, March 21, 2013
expose URL to access local files on server
Sometimes, we need to access local files on server via HTTP URL. If the files are under /webapp/<project>, take tomcat as an example, it is very east to access them via relative path. If the files are outside of tomcat or other web app servers, how to resolve it?
1) create soft link at /var/www/html/<your root context>
ln -s <file location on server> imgupload
2) modify apache setting
<Directory />
Options FollowSymlinks
Allow from all
</Directory>
refer to http://httpd.apache.org/docs/2.2/mod/core.html
3) then on web page
<img src="/imgupload/<subfolder if have>/abc.jpg" />
Tuesday, March 5, 2013
use JSTL to render image blob
1) on DB level, use byte[] to present image
private byte[] image
2) on servlet level, encode byte[] with Base64
String imageBase64=Base64.encode(image);
3)
<img src="data:image/jpg;base64, ${base64Image} " height="152" width="267"/>
private byte[] image
2) on servlet level, encode byte[] with Base64
String imageBase64=Base64.encode(image);
3)
<img src="data:image/jpg;base64, ${base64Image} " height="152" width="267"/>
Friday, February 22, 2013
Spring AOP Logging Example
In general, we print the input arguments and output response for debugging. If we add log statements in each methods, it is very troublesome, spring provides AOP make it easy.
1) add this configuration
<aop:aspectj-autoproxy />
2)
@Component
@Aspect
public class ServiceLoggingAspect extends ServiceBase {
@Around("execution(* com.abc.service.impl.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
info("[" + joinPoint.getTarget().getClass().getName() + "]."
+ joinPoint.getSignature().getName(),
" return " + result + " with arguments : "
+ Arrays.toString(joinPoint.getArgs())
+ ", Time to execute : "
+ (System.currentTimeMillis() - startTime) + "ms");
return result;
} catch (Exception e) {
error("[" + joinPoint.getTarget().getClass().getName() + "]."
+ joinPoint.getSignature().getName(),
"Exception occured with arguments : "
+ Arrays.toString(joinPoint.getArgs())
+ ", Time to execute : "
+ (System.currentTimeMillis() - startTime) + "ms",
e);
throw e;
}
}
}
1) add this configuration
<aop:aspectj-autoproxy />
2)
@Component
@Aspect
public class ServiceLoggingAspect extends ServiceBase {
@Around("execution(* com.abc.service.impl.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
Long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
info("[" + joinPoint.getTarget().getClass().getName() + "]."
+ joinPoint.getSignature().getName(),
" return " + result + " with arguments : "
+ Arrays.toString(joinPoint.getArgs())
+ ", Time to execute : "
+ (System.currentTimeMillis() - startTime) + "ms");
return result;
} catch (Exception e) {
error("[" + joinPoint.getTarget().getClass().getName() + "]."
+ joinPoint.getSignature().getName(),
"Exception occured with arguments : "
+ Arrays.toString(joinPoint.getArgs())
+ ", Time to execute : "
+ (System.currentTimeMillis() - startTime) + "ms",
e);
throw e;
}
}
}
Take note: The runtime exception will not be printed, but checked exception will be printed.
Spring Transaction Rollback
- transaction rollback testing
public interface AccountDao {
public void addAccount(Account account) ;
}
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private SessionFactory sessionFactory;
public void addAccount(Account account) {
sessionFactory.getCurrentSession().save(account);
}
}
2) class in service layer
@Transactional(rollbackFor=DBException.class)
public interface AccountService {
public void addAccount(Account account) throws DBException;
}
DBException is a self-defined checked exception.
Only unchecked exceptions (that is, subclasses of java.lang.RuntimeException) are rollbacked by default in spring. If want to roll back for checked exception, need to declare by this way @Transactional(rollbackFor=DBException.class)
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void addAccount(Account account) throws DBException{
try {
accountDao.addAccount(account);
} catch (Exception e) {
e.printStackTrace();
throw new DBException(DBException.ERR_ADD_ACCOUNTS,
e);
}
}
}
3) junit test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:spring-context-service-test.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public class AccountServiceTester {
@Autowired
AccountService accountService;
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
@Rollback(false)
public void testAccount2() throws DBException{
Account account=new Account();
account.setUserid("0011abc22");
account.setPassword("111");
account.setTimeStamp(new Date());
accountService.addAccount(account);
Account account2=new Account();
account2.setUserid("0011abc22");
account2.setPassword("222");
account2.setTimeStamp(new Date());
accountService.addAccount(account2);
}
@Test
@Rollback(false)
public void testAccount3() throws DBException{
Account account=new Account();
account.setUserid("0011abc4");
account.setPassword("111");
account.setTimeStamp(new Date());
accountService.addAccount(account);
}
@Test
@Rollback(false)
public void testAccount4() throws DBException{
Account account=new Account();
account.setUserid("0011abc4");
account.setPassword("222");
account.setTimeStamp(new Date());
accountService.addAccount(account);
}
}
@Rollback(false) means the data will be committed into database, otherwise spring will rollback all DB operations.
userId is the private key in DB.
Test Result:
a) The data in method testAccount2() will not be committed to database because the two accountService.addAccount(account) share the same DB transaction and DB will rollback due to duplicate key error
b) The data in method testAccount3() will be committed to database as it is a standalone DB transaction
c) The data in method testAccount4() will not be committed to database due to duplicate key error even it is a standalone DB transaction
- how to use
dao.method1();
....
...
// do something
...
...
dao.method2();
}
It is not good to write the source code if dao.method1() and dao.method2() do NOT share the same DB transaction. If writing code as above, the two dao methods will share the same DB transaction.
what we can do is to write a private method to call the two dao methods individually.
Based on the description in http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
PROPAGATION_REQUIRES_NEW
PROPAGATION_REQUIRES_NEW, in contrast to PROPAGATION_REQUIRED, uses a completely independent transaction for each affected transaction scope. In that case, the underlying physical transactions are different and hence can commit or roll back independently, with an outer transaction not affected by an inner transaction's rollback status.public void addAccount2() throws DBException;
public void addAccount3() throws DBException;
in the implementation class,
@Transactional(propagation=Propagation.REQUIRES_NEW, rollbackFor=DBException.class)
public void addAccount2() throws DBException{
Account account=new Account();
account.setUserid("ccc444");
account.setPassword("111");
account.setTimeStamp(new Date());
try{
accountDao.addAccount(account);
}catch(Exception e){
e.printStackTrace();
throw new DBException(DBException.ERR_ADD_ACCOUNTS,
e);
}
}
@Transactional(propagation=Propagation.REQUIRES_NEW, rollbackFor=DBException.class)
public void addAccount3() throws DBException{
Account account=new Account();
account.setUserid("ccc444");
account.setPassword("222");
account.setTimeStamp(new Date());
try{
accountDao.addAccount(account);
}catch(Exception e){
e.printStackTrace();
throw new DBException(DBException.ERR_ADD_ACCOUNTS,
e);
}
}
in the junit class,
@Test
@Rollback(false) public void testAccount5() throws Exception{
accountService.addAccount2();
accountService.addAccount3();
}
then the two methods have their own DB transactions.
Wednesday, February 20, 2013
Add Total Row in jQuery DataTables
1) json response written by spring mvc 3
@RequestMapping(value = "/getTestData", produces = "application/json")
public @ResponseBody List<TestData> getTestDataTable() {
List<TestData> result = new ArrayList<TestData>();
TestData d1 = new TestData();
d1.setName("Hello A");
d1.setNuma(1100);
d1.setNumb(7);
TestData d2 = new TestData();
d2.setName("B hello");
d2.setNuma(3412);
d2.setNumb(5);
result.add(d1);
result.add(d2);
return result;
}
This is the response sample:
2) add a table in html
<table id="id_dt_test" class="display">
<thead>
<tr>
<th width="20%">Name</th>
<th width="20%">Number A</th>
<th width="20%">Number B</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<th style="text-align: right">Total:</th>
<th style="text-align: left"></th>
<th style="text-align: left"></th>
</tr>
</tfoot>
</table>
3) init datatables
$('#id_dt_test').dataTable({
"bProcessing" : true,
"bDestroy" : true,
"sAjaxSource" : 'getTestData.do',
"sAjaxDataProp" : "",
"bFilter" : false,
"bInfo" : false,
"bLengthChange" : false,
"aoColumns" : [ {
"mData" : "name"
}, {
"mData" : "numa",
}, {
"mData" : "numb"
} ],
"bPaginate" : false,
"bAutoWidth" : false,
"fnFooterCallback" : function(nRow, aaData, iStart, iEnd,
aiDisplay) {
var iTotalNuma = 0;
var iTotalNumb = 0;
if (aaData.length > 0) {
for ( var i = 0; i < aaData.length; i++) {
iTotalNuma += aaData[i].numa;
iTotalNumb += aaData[i].numb;
}
}
/*
* render the total row in table footer
*/
var nCells = nRow.getElementsByTagName('th');
nCells[1].innerHTML = iTotalNuma;
nCells[2].innerHTML = iTotalNumb;
}
});
4) actual result:
Reference URL:
http://datatables.net/release-datatables/examples/advanced_init/footer_callback.html
@RequestMapping(value = "/getTestData", produces = "application/json")
public @ResponseBody List<TestData> getTestDataTable() {
List<TestData> result = new ArrayList<TestData>();
TestData d1 = new TestData();
d1.setName("Hello A");
d1.setNuma(1100);
d1.setNumb(7);
TestData d2 = new TestData();
d2.setName("B hello");
d2.setNuma(3412);
d2.setNumb(5);
result.add(d1);
result.add(d2);
return result;
}
This is the response sample:
[{"name":"Hello A","numa":1100,"numb":7},{"name":"B hello","numa":3412,"numb":5}]
2) add a table in html
<table id="id_dt_test" class="display">
<thead>
<tr>
<th width="20%">Name</th>
<th width="20%">Number A</th>
<th width="20%">Number B</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<th style="text-align: right">Total:</th>
<th style="text-align: left"></th>
<th style="text-align: left"></th>
</tr>
</tfoot>
</table>
3) init datatables
$('#id_dt_test').dataTable({
"bProcessing" : true,
"bDestroy" : true,
"sAjaxSource" : 'getTestData.do',
"sAjaxDataProp" : "",
"bFilter" : false,
"bInfo" : false,
"bLengthChange" : false,
"aoColumns" : [ {
"mData" : "name"
}, {
"mData" : "numa",
}, {
"mData" : "numb"
} ],
"bPaginate" : false,
"bAutoWidth" : false,
"fnFooterCallback" : function(nRow, aaData, iStart, iEnd,
aiDisplay) {
var iTotalNuma = 0;
var iTotalNumb = 0;
if (aaData.length > 0) {
for ( var i = 0; i < aaData.length; i++) {
iTotalNuma += aaData[i].numa;
iTotalNumb += aaData[i].numb;
}
}
/*
* render the total row in table footer
*/
var nCells = nRow.getElementsByTagName('th');
nCells[1].innerHTML = iTotalNuma;
nCells[2].innerHTML = iTotalNumb;
}
});
4) actual result:
Reference URL:
http://datatables.net/release-datatables/examples/advanced_init/footer_callback.html
Wednesday, February 6, 2013
css/js files are locked if running in jetty
css/js files are not allowed to edit if running in maven jetty plugin, so it is very troublesome to restart jetty if need to edit css/js files.
- why
- solution
<param-name>useFileMappedBuffer</param-name><param-value>true</param-value> <!-- change to false -->
if you are using maven jetty plugin in eclipse, how to find the file webdefault.xml
refer to http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin
for the plugin, the file webdefault.xml in jar file jetty-webapp.jar
so go to %user%\.m2\repository\org\eclipse\jetty\jetty-webapp\{jetty version}\jetty-webapp-{jetty version}.jar
open org/mortbay/jetty/webapp/webdefault.xml and change the configuration mentioned above
Subscribe to:
Posts (Atom)