3. Who Am I
• 葉政達 Cheng-Ta Yeh
• Co-founder of Humus Technology (優沃科技)
• Founder of GOGOSamba (Android app & Calorie Management Service)
• Speaker of TWJUG 2012/5
• Speaker of Google Developer Day 2008
• Speaker of Java One Tokyo 2005
• 12 years Java related experiences
12年7月19日星期四
10. Problems ...
• Few conventions and standards
12年7月19日星期四
11. Problems ...
• jQuery is cool, it has plenty of selectors
and callbacks, but ...
ily
We have to tie d ata to the DOM heav
,
ca llbacks’ callbacks’...
We have to deal with ts......
to manipulate DO M, animations, even
http://mysistersjar.wordpress.com/2008/04/02/wanted-moving-boxes/
12年7月19日星期四
12. Problems ...
• Between server-side and client-side, we
need efficient tools.
12年7月19日星期四
15. Backbone Components
Template
Render DOM
UI
Use DOM events
Hash tag
View Talks Model / Data
Router
Fragment
routing
Model events
Collection
sync Source
Morning
hashchange
Dispatching routers
History Event
12年7月19日星期四
16. Backbone View
• Owns a DOM element
• Talks to its model or collection
• Observe model events (change,...)
• Handle user’s inputs (DOM events)
12年7月19日星期四
17. Backbone Model
• Data storage and business logic
• Changes on the attributes will fire
`change` event
• Talks to server uses RESTful JSON
12年7月19日星期四
27. Standards for Modules
• CommonJS Modules 1.1.1
• Targeted at server-side environments
• AMD (Asynchronous Module Definition)
• A format for writing modular javascript in the browser
on JS
m m
Co
12年7月19日星期四
28. RequirJS AMD Loader
Other AMD loaders:
• curl
• lsjs
• Dojo 1.7 and MooTools 2.0 each have their own
12年7月19日星期四
31. Your App’s Entry Point
require.config({
// .....
})
./views/itemView.js
require(['jquery','app'],
function ($,app) {
app.initial();
});
Load Load
./main.js
define([../views/itemView],function (itemView) {
return {
1. Set up requireJS configuration.
2. Start to run your app. Execute initial: function(){
// Do initialization.....
// Render first App’s screen.
itemView.render();
1. As a top level container.
},
2. Initialize your app.
4. Render your first screen. };
}); ./app.js
12年7月19日星期四
32. Set up your HTML Page
<!DOCTYPE html>
<html>
<head>
<title>jQuery+RequireJS Sample Page</title>
<script data-main="scripts/main" src="scripts/require-jquery.js"></script>
</head>
<body>
<h1>Single Page Application Sample Page</h1>
<div id=”app_body”>
Your DOM elements will be inserted dynamically.
</div>
</body>
</html>
12年7月19日星期四
33. Using requireJS Optimizer
• Optimizing all the CSS and JS files in your
project
> r.js -o app.build.js
({
appDir: "../",
baseUrl: "scripts",
dir: "../../appdirectory-build",
modules: [
{
name: "main"
}
]
})
app.build.js
12年7月19日星期四
34. Tips & Lessons Learned
• Prevent Memory Leaks
• All models, collections, views implement destructors.
• Create an abstraction layer for those destructors.
Backbone.View.prototype.close = function () {
console.log("Closing a View...”);
if (this.beforeClose) {
this.beforeClose();
}
this.remove();
this.unbind();
};
12年7月19日星期四
37. Backbone Model &
RESTful JSON Inteface
C itemModel.save(); • POST /items
R itemModel.fetch(); • GET /items[/{id}]
U itemModel.save(); • PUT /items/{id}
D itemModel.clear(); • DELETE /items/{id}
* POST or PUT base on the id value of Model.
* Global ajax error handler is useful
12年7月19日星期四
38. Define RESTful Interface
• Nouns: URI, addressed resources
• /sites
• /sites/{id}
• /sites/{id}/items
• /sites/{id}/items/{todoId}.
Find your resources BEFORE
designing Backbone Models and
The REST Triangle
Spring MVC Controller methods.
12年7月19日星期四
40. Receiving Values in the URL Path
• The RESTful way
• @PathVariable in Controller methods
@RequestMapping(value="/sites/{siteId}/item/{itemId}",method= {RequestMethod.PUT})
public @ResponseBody UIJentoItem updateModule(@PathVariable long siteId,@PathVariable Long itemId,@Valid
@RequestBody UIJentoItem item) {
UIJentoItem uiObject = new UIJentoItem();
//......
return uiObject;
}
12年7月19日星期四
41. Sending HTTP Response Codes
to Clients AbstractController
• @ResponseStatus extends
• @ExecptionHandler. Controller Controller Controller
A B C
public class AbstractController {
@ExceptionHandler(UserNotSigninException.class)
@ResponseStatus(UNAUTHORIZED) // HTTP 401
public @ResponseBody UIMessage handleUserNotSigninException(UserNotSigninException e, HttpServletResponse response)
{
return UIMessage.fail("err.data.usernotsignin");
}
@ExceptionHandler(DataNotFoundException.class)
@ResponseStatus(NOT_FOUND) // HTTP 404
public @ResponseBody UIMessage handleDataNotFoundException(DataNotFoundException e, HttpServletResponse response) {
return UIMessage.fail("err.data.notfound");
}
@ExceptionHandler(Exception.class)
@ResponseStatus(INTERNAL_SERVER_ERROR)// HTTP 505
public @ResponseBody UIMessage handleException(Exception e, HttpServletResponse response) {
return UIMessage.fail("err.internal");
}
}
12年7月19日星期四
42. Rarely Need Custom Parsers
• Automatically registers several converters.
12年7月19日星期四
43. Controller Methods’
Parameters and Return Values
ween
s bet ing MVC
he b ullet Spr
T del &
bon e Mo
Back
12年7月19日星期四
44. Parameters and Return Values
• Domain Entity
Controller
@RequestMapping(value="/sites/{id}/items",method= {RequestMethod.GET})
@ResponseStatus(OK)
public @ResponseBody List<Item> getItems(@PathVariable long id) {
//.... Out
return itemList;
}
@RequestMapping(value="/sites/{id}/items",method= {RequestMethod.POST})
@ResponseStatus(OK)
public @ResponseBody String createItem(
@PathVariable long id,@RequestBody Item item) {
//.... In
}
Controller
12年7月19日星期四
45. Parameters and Return Values
• DTO (Data Transfer Object)
Controller
@RequestMapping(value="/sites/{id}/items",method= {RequestMethod.GET})
@ResponseStatus(OK)
public @ResponseBody List<DTOItem> getItems(@PathVariable long id) {
//.... Out
return itemList;
}
@RequestMapping(value="/sites/{id}/items",method= {RequestMethod.POST})
@ResponseStatus(OK)
public @ResponseBody String createItem(
@PathVariable long id,@RequestBody DTOItem item) {
//....
}
In
Controller
12年7月19日星期四
46. Parameters and Return Values
• JSONObject
Controller
import net.sf.json.JSONObject;
@RequestMapping(value="/sites/{id}/items",method= {RequestMethod.GET})
@ResponseStatus(OK)
public @ResponseBody List<JSONObject> getItems(@PathVariable long id) {
//....
Out
return itemList;
}
@RequestMapping(value="/sites/{id}/items",method= {RequestMethod.POST})
@ResponseStatus(OK)
public @ResponseBody String createItem(
@PathVariable long id, @RequestBody JSONObject itemJSON) {
//....
In
}
Controller
12年7月19日星期四
47. Parameters and Return Values
• Domain Entity
• Pros: No extra effort for creation and maintenance & readable
• Cons: Might waste extra bandwidth for transferring
• DTO
• Pros: readable
• Cons: Extra efforts for maintenance, transferring from domain
object to DTO.
• JSONObject
• Pros: No extra effort for creation and maintenance
• Cons: Not readable, Unit testing is mandatory, transferring from
domain entity to JSONObject!
12年7月19日星期四
48. Unit Test for Spring MVC
Controller
• mockito - Mocking framework
• http://code.google.com/p/mockito/
• Spring MVC Test Support
• https://github.com/SpringSource/spring-test-mvc
12年7月19日星期四
49. Unit Test for Spring MVC
Controller
public class ItemControllerTest { ItemController
private static MockMvc mockMvc; use use
private UserSerivce userService;
private ItemSerivce itemService;
ItemService UserService
@Before
public void setUp() {
userService = mock(UserService.class);
itemService = mock(ItemService.class); Create a mock service
Setup mockMVC for target Controller
mockMvc = standaloneSetup(new ItemController()).build();
// userService.getCurrentUser() will be called in ItemController for URI "/sites/{id}/items"
when(userService.getCurrentUser()).thenReturn(new User());
Item item = new Item();
item.setName("This is item name");
when(itemService.getItem(any(Long.class))).thenReturn(item);
}
tell mocks when some calls happened return something
@Test
public void getItemsBySiteId() throws Exception {
mockMvc.perform(get("/sites/1/items"))
.andExpect(status().isOk()) Your URI
.andExpect(content().type("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.[0].id").value(1))
.andExpect(jsonPath("$.[0].itemName").value("This is item name"))
;
12年7月19日星期四
51. Layer Architecture
Backbone.js requireJS HTML
Spring MVC
Domain Model
Spring Data JPA
12年7月19日星期四
52. Between Spring MVC and
Spring Data JPA
• Data conversion
• Design concept
12年7月19日星期四
53. Between Spring MVC and
Spring Data JPA
• Data conversion
• Using Factory Method in Domain entity or separate Factory classes.
DTO JSONObject
Spring MVC
Domain Object
Spring Data JPA
12年7月19日星期四
54. Between Spring MVC and
Spring Data JPA
• Data conversion
• Using Factory Method in Domain entity or separate Factory classes.
@Entity
public class Item implements Serializable {
private String name;
//.....
public JSONObject toJSON(){
DTO JSONObject JSONObject object = new JSONObject();
//Converting Item to JSONObject.
object.put("name", this.name);
return object;
}
Domain Object
public static Item fromJSON(JSONObject json){
//Converting JSONObject to Item.
return item;
}
}
12年7月19日星期四
55. Between Spring MVC and
Spring Data JPA
• Design concept
• Domain driven design in Domain Layer
• Entity
• Service
• Value Object
• Aggregate
• Repository Spring Data borrows this concept.
12年7月19日星期四
56. Spring Data Overview
• Abstracts away basic data management concepts
• Support for RDB, NoSQL: Graph, Key-Value and Map-Reduce
types.
• Current implementations
• JPA/JDBC
• Hadoop
• GemFire
• REST
• Redis/Riak
• MongoDB
• Neo4j
• Blob (AWS S3, Rackspace, Azure,...)
• Plan for HBase and Cassandra
12年7月19日星期四
58. The Domain Entities
@Entity
public class Site {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// … methods omitted
}
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
1 private Long id;
Site *
Item @ManyToOne
private Site site;
// … methods omitted
}
12年7月19日星期四
59. The DAO
@Repository
public class TodoDAO {"
@PersistenceContext
private EntityManager em;
@Override
@Transactional
public Item save(Item item) {
if (item.getId() == null) {
em.persist(item);
return item;
} else {
return em.merge(item);
}
}
@Override
public List<Item> findBySiteId(Long siteId) {
TypedQuery query = em.createQuery("select i from Item a where i.site.id = ?1", Item.class);
query.setParameter(1, siteId);
return query.getResultList();
}
}
12年7月19日星期四
60. The Domain Service
@Service
@Transactional(readOnly = true)
class ItemListServiceImpl implements ItemListService {
@Autowired
private ItemDAO itemDAO;
@Override
@Transactional
public Item save(Item item) {
return itemDAO.save(item);
}
@Override
public List<Item> findItems(Long siteId) {
return itemDAO.findBySiteId(siteId);
}
}
12年7月19日星期四
62. The Repository (DAO)
public interface ItemRepository extends JpaRepository<Item, Long>
{
List<Item> findBySite(Site site);
}
12年7月19日星期四
63. The Service
@Service
@Transactional(readOnly = true)
class ItemListServiceImpl implements ItemListService {
@Autowired
private ItemRepository repository;
@Override
@Transactional
public Item save(Item item) {
return repository.save(item);
}
@Override
public List<Item> findItems(Site site) {
return repository.findBySite(site);
}
}
12年7月19日星期四
64. Strategy: CREATE
• Split your query methods by prefix and
property names.
12年7月19日星期四
65. Strategy:
USE_DECLARED_QUERY
• @Query
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
From Spring Data JPA 1.1.0, native SQL is allowed to be
executed. Just set nativeQuery flag to true.
But, not support pagination and dynamic sort
12年7月19日星期四
66. Strategy:
USE_DECLARED_QUERY
• @Modify
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
@Modifying
@Query("update User u set u.firstname = :firstName where u.lastname = :lastName")
int setFixedFirstnameFor(@Param("firstName") String firstname, @Param("lastName") String lastname);
12年7月19日星期四
67. Configurations in Spring 3.1
<!-- Activate Spring Data JPA repository support -->
<jpa:repositories base-package="com.humus.domain.repo" />
<!-- Declare a JPA entityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.humus.domain.entity</value>
</list>
</property>
</bean>
No persistence.xml any more~
12年7月19日星期四
68. Put It All Together
Backbone.js
requireJS
Spring MVC
Spring Data JPA
12年7月19日星期四
69. The End & Thank You
http://about.me/ctyeh
12年7月19日星期四