1 数据模型
表关系如图
![](https://img.haomeiwen.com/i5315044/eb6ade93cb3ec1a1.png)
定义Product Model
@Entity
@Table(name = "ESPM_PRODUCT")
@NamedQueries({
@NamedQuery(name = "Product.getProductByProductId", query = "SELECT p FROM Product p where p.productId = :productId"),
@NamedQuery(name = "Product.getAllProducts", query = "SELECT p FROM Product p"),
@NamedQuery(name = "Product.getProductByCategory", query = "SELECT p FROM Product p WHERE p.category = :category")
})
public class Product {
transient private static Map<String, BigDecimal> prices = null;
@Id
@Column(name = "PRODUCT_ID", length = 10)
private String productId;
private String name;
@Column(name = "SHORT_DESCRIPTION")
private String shortDescription;
@Column(name = "LONG_DESCRIPTION")
private String longDescription;
@Column(length = 40)
private String category;
@Column(name = "CATEGORY_NAME", length = 40)
private String categoryName;
@Column(name = "QUANTITY_UNIT", length = 3)
private String quantityUnit;
@Column(name = "WEIGHT", precision = 13, scale = 3)
private BigDecimal weight;
@Column(name = "WEIGHT_UNIT", length = 3)
private String weightUnit;
@Column(precision = 23, scale = 3)
private BigDecimal price;
@Column(name = "CURRENCY_CODE", length = 5)
private String currencyCode = "EUR";
@Column(name = "DIMENSION_WIDTH", precision = 13, scale = 4)
private BigDecimal dimensionWidth;
@Column(name = "DIMENSION_DEPTH", precision = 13, scale = 4)
private BigDecimal dimensionDepth;
@Column(name = "DIMENSION_HEIGHT", precision = 13, scale = 4)
private BigDecimal dimensionHeight;
@Column(name = "DIMENSION_UNIT", length = 3)
private String dimensionUnit;
@Column(name = "PICTURE_URL")
private String pictureUrl;
@Column(name = "SUPPLIER_ID", length = 10)
private String supplierId;
@OneToOne //OData Navigation
private Supplier supplier;
@OneToMany(mappedBy = "product", targetEntity = CustomerReview.class, fetch = FetchType.EAGER) //OData Navigation
private List<CustomerReview> reviews;
public Product() {
this.reviews = new ArrayList<CustomerReview>();
}
// set & get method for fields
// set&get method for Customer Review
public void addReview(CustomerReview review) {
this.reviews.add(review);
}
public List<CustomerReview> getReviews() {
return this.reviews;
}
//根据id获取price
static BigDecimal getPrice(String productId) {
if (prices == null) {
updatePrices();
}
return prices.get(productId);
}
//取出所有product的price
private static void updatePrices() {
EntityManagerFactory emf = Utility.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
try {
List<Product> products = em.createQuery("SELECT p FROM Product p", Product.class).getResultList();
prices = new HashMap<String, BigDecimal>();
for (Product p : products) {
prices.put(p.getProductId(), p.getPrice());
}
} finally {
em.close();
}
}
//无效的price
private static void invalidatePrices() {
if (prices != null) {
prices.clear();
}
prices = null;
}
//更新后,取出product text
@PostLoad
private void postLoad() {
EntityManagerFactory emf = Utility.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
try {
ProductText productText = getProductText(em);
if (productText != null) {
this.name = productText.getName();
this.shortDescription = productText.getShortDescription();
this.longDescription = productText.getLongDescription();
} else {
this.name = "";
this.shortDescription = "";
this.longDescription = "";
}
} finally {
em.close();
}
}
//更新前先更新text表
@PrePersist
@PreUpdate
private void persist() {
EntityManagerFactory emf = Utility.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
ProductText productText = getProductText(em);
if (productText == null) {
// INSERT
productText = new ProductText();
productText.setProductId(this.getProductId());
productText.setLanguage("EN");
productText.setName(this.name);
productText.setShortDescription(this.shortDescription);
productText.setLongDescription(this.longDescription);
em.persist(productText);
} else {
// UPDATE
productText.setName(this.name);
productText.setShortDescription(this.shortDescription);
productText.setLongDescription(this.longDescription);
}
em.getTransaction().commit();
} finally {
// ProductCategory.invalidateNumbers();
invalidatePrices();
em.close();
}
}
//取text表的描述
private ProductText getProductText(EntityManager em) {
TypedQuery<ProductText> query = em.createQuery(
"SELECT p FROM ProductText p WHERE p.productId = :productId AND p.language = :language",
ProductText.class);
try {
return query.setParameter("productId", this.getProductId()).setParameter("language", "EN")
.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
public Map<String, String> getProductReportMap() {
Map<String, String> productMap = new LinkedHashMap<>(2);
productMap.put("shortDescription", shortDescription);
productMap.put("price", String.valueOf(price));
return productMap;
}
}
定义Supplier Model
@Entity
@Table(name = "ESPM_SUPPLIER")
@NamedQueries({
@NamedQuery(name = "Supplier.getAllSuppliers", query = "SELECT s FROM Supplier s"),
@NamedQuery(name = "Supplier.getSupplierBySupplierId", query = "SELECT s FROM Supplier s WHERE s.supplierId= :supplierId")
})
public class Supplier {
/* Supplier ids are generated within a number range starting with 2 */
@TableGenerator(name = "SupplierGenerator", table = "ESPM_ID_GENERATOR", pkColumnName = "GENERATOR_NAME", valueColumnName = "GENERATOR_VALUE", pkColumnValue = "Customer", initialValue = 100000000, allocationSize = 100)
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "SupplierGenerator")
@Column(name = "SUPPLIER_ID", length = 10)
private String supplierId;
@Column(name = "EMAIL_ADDRESS", unique = true)
private String emailAddress;
@Column(name = "PHONE_NUMBER", length = 30)
private String phoneNumber;
@Column(name = "CITY", length = 40)
private String city;
@Column(name = "POSTAL_CODE", length = 10)
private String postalCode;
@Column(name = "STREET", length = 60)
private String street;
@Column(name = "HOUSE_NUMBER", length = 10)
private String houseNumber;
@Column(name = "COUNTRY", length = 3)
private String country;
@Column(name = "SUPPLIER_NAME", length = 80)
private String supplierName;
public String getSupplierId() {
return supplierId;
}
// set & get method
定义CustomerReview Model
@Entity
@Table(name = "ESPM_EXTENSION_CUSTOMER_REVIEW")
@NamedQuery(name = "CustomerReview.getAllCustomerReviews", query = "SELECT cr FROM CustomerReview cr")
public class CustomerReview implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "CUSTOMER_REVIEW_ID", length = 16)
private String customerReviewId;
@Column(name = "COMMENT", length = 1024)
private String comment;
@Column(name = "RATING")
private int rating;
@Column(name = "PRODUCT_ID", length = 10)
private String productId;
@Column(name = "DATE_OF_CREATION")
@Temporal(TemporalType.TIMESTAMP)
private Calendar creationDate;
@Column(name = "FIRST_NAME", length = 40)
private String firstName;
@Column(name = "LAST_NAME", length = 40)
private String lastName;
@ManyToOne(optional=false)
private Product product;
public CustomerReview() {
super();
}
定义SalesOrderHeader Model
@Entity
@Table(name = "ESPM_SALES_ORDER_HEADER")
@NamedQueries({
@NamedQuery(name = "SalesOrderHeader.getSOHBySaledOrderId", query = "SELECT soh FROM SalesOrderHeader soh WHERE soh.salesOrderId= :salesOrderId"),
@NamedQuery(name = "SalesOrderHeader.getSOHByCustomerId", query = "SELECT soh FROM SalesOrderHeader soh WHERE soh.customerId= :customerId")
})
public class SalesOrderHeader {
/* Sales order ids are generated within a number range starting with 5 */
@TableGenerator(name = "SalesOrderGenerator", table = "ESPM_ID_GENERATOR", pkColumnName = "GENERATOR_NAME", valueColumnName = "GENERATOR_VALUE", pkColumnValue = "SalesOrder", initialValue = 500000000, allocationSize = 100)
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "SalesOrderGenerator")
@Column(name = "SALES_ORDER_ID", length = 10)
private String salesOrderId;
@Column(name = "CUSTOMER_ID", length = 10)
private String customerId;
@Column(name = "CURRENCY_CODE", length = 5)
private String currencyCode = "EUR";
@Column(name = "GROSS_AMOUNT", precision = 15, scale = 3)
private BigDecimal grossAmount;
@Column(name = "NET_AMOUNT", precision = 15, scale = 3)
private BigDecimal netAmount;
@Column(name = "TAX_AMOUNT", precision = 15, scale = 3)
private BigDecimal taxAmount;
@Column(name = "LIFE_CYCLE_STATUS", length = 1, nullable = false)
private String lifeCycleStatus;
@Column(name = "LIFE_CYCLE_STATUS_NAME", nullable = false)
private String lifeCycleStatusName;
@Column(name = "CREATED_AT")
@Temporal(TemporalType.DATE)
private Calendar createdAt;
@Column(name = "INVOICE_LINK", length = 200)
private String invoiceLink;
@OneToOne
private Customer customer;
@OneToMany(mappedBy = "salesOrderHeader", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<SalesOrderItem> salesOrderItems;
public SalesOrderHeader() {
this.salesOrderItems = new ArrayList<SalesOrderItem>();
}
//set & get method
@PrePersist
private void persist() {
Calendar cal = Calendar.getInstance();
Date date = new Date();
cal.setTime(date);
this.lifeCycleStatus = "N";
this.lifeCycleStatusName = "New";
int itemNumber = 10;
this.netAmount = new BigDecimal("0.00");
this.taxAmount = new BigDecimal("0.00");
this.grossAmount = new BigDecimal("0.00");
this.createdAt = cal;
for (SalesOrderItem item : salesOrderItems) {
item.setSalesOrderId(this.getSalesOrderId());
item.setItemNumber(itemNumber);
itemNumber += 10;
item.persist();
this.netAmount = this.netAmount.add(item.getNetAmount())
.setScale(3);
this.taxAmount = this.taxAmount.add(item.getTaxAmount())
.setScale(3);
this.grossAmount = this.grossAmount.add(item.getGrossAmount())
.setScale(3);
}
}
}
定义SalesOrderItem Model
@Entity
@Table(name = "ESPM_SALES_ORDER_ITEM")
@NamedQueries({
@NamedQuery(name = "SalesOrderItem.getSOIBySalesOrderItemId", query = "SELECT soi FROM SalesOrderItem soi WHERE soi.id.salesOrderId= :id"),
@NamedQuery(name = "SalesOrderItem.getSOIByCurrencyCode", query = "SELECT soi FROM SalesOrderItem soi WHERE soi.currencyCode = :currencyCode")
})
public class SalesOrderItem {
private static final BigDecimal TAX_AMOUNT_FACTOR = new BigDecimal("0.19");
private static final BigDecimal GROSS_AMOUNT_FACTOR = new BigDecimal("1.19");
@EmbeddedId
private SalesOrderItemId id;
@Column(name = "PRODUCT_ID", length = 10)
private String productId;
@Column(name = "CURRENCY_CODE", length = 5)
private String currencyCode = "EUR";
@Column(name = "GROSS_AMOUNT", precision = 15, scale = 3)
private BigDecimal grossAmount;
@Column(name = "NET_AMOUNT", precision = 15, scale = 3)
private BigDecimal netAmount;
@Column(name = "TAX_AMOUNT", precision = 15, scale = 3)
private BigDecimal taxAmount;
@Column(precision = 13, scale = 3)
private BigDecimal quantity;
@Column(name = "QUANTITY_UNIT", length = 3)
private String quantityUnit = "EA";
@Column(name = "DELIVERY_DATE")
@Temporal(TemporalType.DATE)
private Calendar deliveryDate;
@OneToOne
private Product product;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinColumn(name = "SALES_ORDER_ITEM_ID", referencedColumnName = "SALES_ORDER_ID", insertable = false, updatable = false)
private SalesOrderHeader salesOrderHeader;
public SalesOrderItem() {
this.id = new SalesOrderItemId();
}
public SalesOrderItem(String salesOrderId, int itemNumber) {
this.id = new SalesOrderItemId(salesOrderId, itemNumber);
}
// set & get method
void persist() {
BigDecimal price = Product.getPrice(this.getProductId());
if (price == null) {
return;
}
this.netAmount = price.multiply(this.getQuantity()).setScale(3);
this.taxAmount = this.netAmount.multiply(TAX_AMOUNT_FACTOR).setScale(3);
this.grossAmount = this.netAmount.multiply(GROSS_AMOUNT_FACTOR)
.setScale(3);
}
}
定义SalesOrderItemId Model
@Embeddable
public class SalesOrderItemId implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name = "SALES_ORDER_ITEM_ID", length = 10)
private String salesOrderId;
@Column(name = "ITEM_NUMBER")
private int itemNumber;
public SalesOrderItemId() {
}
public SalesOrderItemId(String salesOrderId, int itemNumber) {
this.salesOrderId = salesOrderId;
this.itemNumber = itemNumber;
}
//set & get method
@Override
public int hashCode() {
return salesOrderId.hashCode() + itemNumber;
}
@Override //判断itemId相等
public boolean equals(Object obj) {
return ((obj instanceof SalesOrderItemId)
&& this.salesOrderId.equals(((SalesOrderItemId) obj)
.getSalesOrderId()) && (this.itemNumber == ((SalesOrderItemId) obj)
.getItemNumber()));
}
}
定义Customer Moel
@Entity
@Table(name = "ESPM_CUSTOMER")
@NamedQueries({
@NamedQuery(name = "Customer.getCustomerByEmailAddress", query = "SELECT c FROM Customer c WHERE c.emailAddress = :emailAddress"),
@NamedQuery(name = "Customer.getCustomerByCustomerId", query = "SELECT cid FROM Customer cid WHERE cid.customerId= :customerId"),
@NamedQuery(name = "Customer.getAllCustomers", query = "SELECT c FROM Customer c")
})
public class Customer {
/* Customer ids are generated within a number range starting with 1 */
@TableGenerator(name = "CustomerGenerator", table = "ESPM_ID_GENERATOR", pkColumnName = "GENERATOR_NAME", valueColumnName = "GENERATOR_VALUE", pkColumnValue = "Customer", initialValue = 100000000, allocationSize = 100)
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "CustomerGenerator")
@Column(name = "CUSTOMER_ID", length = 10)
private String customerId;
@Column(name = "EMAIL_ADDRESS", unique = true)
private String emailAddress;
@Column(name = "PHONE_NUMBER", length = 30)
private String phoneNumber;
@Column(name = "FIRST_NAME", length = 40)
private String firstName;
@Column(name = "LAST_NAME", length = 40)
private String lastName;
@Column(name = "DATE_OF_BIRTH", nullable = false)
@Temporal(TemporalType.DATE)
private Calendar dateOfBirth;
@Column(name = "CITY", length = 40)
private String city;
@Column(name = "POSTAL_CODE", length = 10)
private String postalCode;
@Column(name = "STREET", length = 60)
private String street;
@Column(name = "HOUSE_NUMBER", length = 10)
private String houseNumber;
@Column(name = "COUNTRY", length = 3)
private String country;
//set & get method
public Map<String, String> getCustomerReportData() {
Map<String, String> customerMapData = new LinkedHashMap<String, String>(7);
customerMapData.put("firstName", firstName);
customerMapData.put("lastName", lastName);
customerMapData.put("houseNumber", houseNumber);
customerMapData.put("emailAddress", emailAddress);
customerMapData.put("phoneNumber", phoneNumber);
customerMapData.put("city", city);
customerMapData.put("street", street);
customerMapData.put("country", country);
return customerMapData;
}
定义ProductCategory Model
@Entity
@Table(name = "ESPM_PRODUCT_CATEGORY")
@NamedQueries({
@NamedQuery(name = "ProductCategory.getAllProductCategories", query = "SELECT pc FROM ProductCategory pc"),
@NamedQuery(name = "ProductCategory.getProductCategoryByCategory", query = "SELECT pc FROM ProductCategory pc WHERE pc.category= :category"),
@NamedQuery(name = "ProductCategory.getProductCategoryByCategoryName", query = "SELECT pc FROM ProductCategory pc WHERE pc.categoryName= :categoryName")
})
public class ProductCategory {
@Id
@Column(length = 40)
private String category;
@Column(name = "CATEGORY_NAME", length = 40)
private String categoryName;
@Column(name = "MAIN_CATEGORY", length = 40)
private String mainCategory;
@Column(name = "MAIN_CATEGORY_NAME", length = 40)
private String mainCategoryName;
@Column(name = "NUMBER_OF_PRODUCTS")
long numberOfProducts;
2 配置
配置persistence.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="test-web" transaction-type="RESOURCE_LOCAL">
<class>model.Customer</class>
<class>model.CustomerReview</class>
<class>model.Product</class>
<class>model.ProductCategory</class>
<class>model.ProductText</class>
<class>model.SalesOrderHeader</class>
<class>model.SalesOrderItem</class>
<class>model.SalesOrderItemId</class>
<class>model.Stock</class>
<class>model.Supplier</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
</properties>
</persistence-unit>
</persistence>
配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>RestProjectTest</display-name>
<servlet>
<servlet-name>ODataServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.apache.olingo.odata2.core.rest.app.ODataApplication</param-value>
</init-param>
<init-param>
<param-name>org.apache.olingo.odata2.service.factory</param-name>
<param-value>web.EmployeeListServiceFactory</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ODataServlet</servlet-name>
<url-pattern>/espm.svc/*</url-pattern>
</servlet-mapping>
<resource-ref>
<res-ref-name>jdbc/DefaultDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
</resource-ref>
<servlet>
<description></description>
<display-name>StartupServlet</display-name>
<servlet-name>StartupServlet</servlet-name>
<servlet-class>web.StartupServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
创建EmployeeListServiceFactory类
public class EmployeeListServiceFactory extends ODataJPAServiceFactory {
private static final String PERSISTENCE_UNIT_NAME = "test-web";
@Override
public ODataJPAContext initializeODataJPAContext()
throws ODataJPARuntimeException {
ODataJPAContext oDatJPAContext = this.getODataJPAContext();
EntityManagerFactory emf;
try {
// EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
emf = JpaEntityManagerFactory.getEntityManagerFactory();
oDatJPAContext.setEntityManagerFactory(emf);
oDatJPAContext.setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
oDatJPAContext.setJPAEdmExtension(new EspmProcessingExtension());
oDatJPAContext.setJPAEdmMappingModel("EspmEdmMapping.xml");
return oDatJPAContext;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
创建EspmProcessingExtension,添加Operation
public class EspmProcessingExtension implements JPAEdmExtension {
/**
* Register function imports.
*/
@Override
public void extendWithOperation(JPAEdmSchemaView view) {
view.registerOperations(CustomerProcessor.class, null);
view.registerOperations(SalesOrderProcessor.class, null);
view.registerOperations(CustomerReviewProcessor.class, null);
}
定义CustomerProcessor,添加getCustomerByEmailAddress方法
public class CustomerProcessor {
@SuppressWarnings("unchecked")
@EdmFunctionImport(name = "GetCustomerByEmailAddress", entitySet = "Customers", returnType = @ReturnType(type = Type.ENTITY, isCollection = true))
public List<Customer> getCustomerByEmailAddress(
@EdmFunctionImportParameter(name = "EmailAddress") String emailAddress) throws ODataException {
EntityManagerFactory emf = Utility.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
List<Customer> custList = null;
try {
Query query = em.createNamedQuery("Customer.getCustomerByEmailAddress");
query.setParameter("emailAddress", emailAddress);
try {
custList = query.getResultList();
return custList;
} catch (NoResultException e) {
throw new ODataApplicationException("No matching customer with Email Address:" + emailAddress,
Locale.ENGLISH, HttpStatusCodes.BAD_REQUEST, e);
}
} finally {
em.close();
}
}
}
定义CustomerReviewProcessor类,添加createCustomerReview方法
public class CustomerReviewProcessor {
@SuppressWarnings("unchecked")
@EdmFunctionImport(name = "CreateCustomerReview", entitySet = "CustomerReviews", returnType = @ReturnType(type = Type.ENTITY, isCollection = false))
public CustomerReview createCustomerReview(@EdmFunctionImportParameter(name = "ProductId") String productId,
@EdmFunctionImportParameter(name = "FirstName") String firstName,
@EdmFunctionImportParameter(name = "LastName") String lastName,
@EdmFunctionImportParameter(name = "Rating") String rating,
@EdmFunctionImportParameter(name = "CreationDate") String creationDate,
@EdmFunctionImportParameter(name = "Comment") String comment) throws ODataException, ParseException {
EntityManagerFactory emf = Utility.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
Product prod = null;
CustomerReview customerReview = null;
try {
em.getTransaction().begin();
prod = em.find(Product.class, productId);
try {
customerReview = new CustomerReview();
customerReview.setComment(comment);
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(Long.parseLong(creationDate)));
customerReview.setCreationDate(cal);
customerReview.setFirstName(firstName);
customerReview.setLastName(lastName);
customerReview.setRating(Integer.parseInt(rating));
customerReview.setProductId(productId);
customerReview.setProduct(prod);
em.persist(customerReview);
if (prod != null) {
prod.addReview(customerReview);
}
em.getTransaction().commit();
return customerReview;
} catch (NoResultException e) {
throw new ODataApplicationException("Error creating customer review:", Locale.ENGLISH,
HttpStatusCodes.BAD_REQUEST, e);
}
} finally {
em.close();
}
}
}
得到的metadata如下
![](https://img.haomeiwen.com/i5315044/43cf390cfef19507.png)
网友评论