diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..9a874b5 Binary files /dev/null and b/.DS_Store differ diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..7b0d367 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000..55c1fcb Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/.DS_Store b/src/main/java/.DS_Store new file mode 100644 index 0000000..8ee47d9 Binary files /dev/null and b/src/main/java/.DS_Store differ diff --git a/src/main/java/edu/.DS_Store b/src/main/java/edu/.DS_Store new file mode 100644 index 0000000..8e05cd7 Binary files /dev/null and b/src/main/java/edu/.DS_Store differ diff --git a/src/main/java/edu/tcu/.DS_Store b/src/main/java/edu/tcu/.DS_Store new file mode 100644 index 0000000..64347c2 Binary files /dev/null and b/src/main/java/edu/tcu/.DS_Store differ diff --git a/src/main/java/edu/tcu/cs/.DS_Store b/src/main/java/edu/tcu/cs/.DS_Store new file mode 100644 index 0000000..c899317 Binary files /dev/null and b/src/main/java/edu/tcu/cs/.DS_Store differ diff --git a/src/main/java/edu/tcu/cs/expensetracker/.DS_Store b/src/main/java/edu/tcu/cs/expensetracker/.DS_Store new file mode 100644 index 0000000..5d62efc Binary files /dev/null and b/src/main/java/edu/tcu/cs/expensetracker/.DS_Store differ diff --git a/src/main/java/edu/tcu/cs/expensetracker/ExpensetrackerApplication.java b/src/main/java/edu/tcu/cs/expensetracker/ExpensetrackerApplication.java index 7faa64b..1de2bfb 100644 --- a/src/main/java/edu/tcu/cs/expensetracker/ExpensetrackerApplication.java +++ b/src/main/java/edu/tcu/cs/expensetracker/ExpensetrackerApplication.java @@ -6,8 +6,8 @@ @SpringBootApplication public class ExpensetrackerApplication { - public static void main(String[] args) { - SpringApplication.run(ExpensetrackerApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(ExpensetrackerApplication.class, args); + } -} +} \ No newline at end of file diff --git a/src/main/java/edu/tcu/cs/expensetracker/controller/ExpenseController.java b/src/main/java/edu/tcu/cs/expensetracker/controller/ExpenseController.java new file mode 100644 index 0000000..55a167e --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/controller/ExpenseController.java @@ -0,0 +1,57 @@ +package edu.tcu.cs.expensetracker.controller; + +import edu.tcu.cs.expensetracker.domain.Expense; +import edu.tcu.cs.expensetracker.domain.Result; +import edu.tcu.cs.expensetracker.domain.StatusCode; +import edu.tcu.cs.expensetracker.service.ExpenseService; + +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.List; + +@RestController +@RequestMapping("/expenses") +public class ExpenseController { + + private ExpenseService expenseService; + + public ExpenseController(ExpenseService expenseService) { + this.expenseService = expenseService; + } + + @GetMapping + public Result findAll(){ + List all = expenseService.findAll(); + Result result = new Result(true, StatusCode.SUCCESS, "Find All Success", all); + return result; + } + @GetMapping("/{expenseId}") + public Result findById(@PathVariable String expenseId) { + return new Result(true, StatusCode.SUCCESS, "Find One Success", expenseService.findById(expenseId)); + } + + @GetMapping("/{expenseStart}/{expenseEnd}") + public Result findById(@PathVariable String expenseStart, @PathVariable String expenseEnd) { + LocalDate expenseStartDate = LocalDate.parse(expenseStart); + LocalDate expenseEndDate = LocalDate.parse(expenseEnd); + return new Result(true, StatusCode.SUCCESS, "Find Between Dates Success", expenseService.findBetweenDates(expenseStartDate, expenseEndDate)); + } + + @PostMapping + public Result save(@RequestBody Expense newExpense){ + expenseService.save(newExpense); + return new Result(true, StatusCode.SUCCESS, "Save Success"); + } + @PutMapping("/{expenseId}") + public Result update(@PathVariable String expenseId, @RequestBody Expense updatedExpense) { + expenseService.update(expenseId, updatedExpense); + return new Result(true, StatusCode.SUCCESS, "Update Success"); + } + @DeleteMapping("/{expenseId}") + public Result delete(@PathVariable String expenseId){ + expenseService.delete(expenseId); + return new Result(true, StatusCode.SUCCESS, "Delete Success"); + + } +} diff --git a/src/main/java/edu/tcu/cs/expensetracker/dao/ExpenseDao.java b/src/main/java/edu/tcu/cs/expensetracker/dao/ExpenseDao.java new file mode 100644 index 0000000..814ec8f --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/dao/ExpenseDao.java @@ -0,0 +1,7 @@ +package edu.tcu.cs.expensetracker.dao; + +import edu.tcu.cs.expensetracker.domain.Expense; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ExpenseDao extends JpaRepository { +} diff --git a/src/main/java/edu/tcu/cs/expensetracker/datainitializer/ExpenseDataInitializer.java b/src/main/java/edu/tcu/cs/expensetracker/datainitializer/ExpenseDataInitializer.java new file mode 100644 index 0000000..66ebd4f --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/datainitializer/ExpenseDataInitializer.java @@ -0,0 +1,147 @@ +package edu.tcu.cs.expensetracker.datainitializer; + +import edu.tcu.cs.expensetracker.dao.ExpenseDao; +import edu.tcu.cs.expensetracker.domain.Expense; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class ExpenseDataInitializer implements CommandLineRunner { + + private ExpenseDao expenseDao; + + public ExpenseDataInitializer(ExpenseDao expenseDao) { + this.expenseDao = expenseDao; + } + + @Override + public void run(String... args) throws Exception { + Expense e1 = new Expense(); + e1.setId("1"); + e1.setName("Dining Spending"); + e1.setMoney("247"); + e1.setAccount("Chase Bank"); + e1.setCreateTime("2016-03-02"); + e1.setDescription("Dutch Burger"); + + Expense e2 = new Expense(); + e2.setId("2"); + e2.setName("Salary Income"); + e2.setMoney("3000"); + e2.setAccount("Cash"); + e2.setCreateTime("2016-03-15"); + e2.setDescription("September Salary"); + + Expense e3 = new Expense(); + e3.setId("3"); + e3.setName("Books Spending"); + e3.setMoney("200"); + e3.setAccount("Cash"); + e3.setCreateTime("2016-04-02"); + e3.setDescription("Calculus Book"); + + Expense e4 = new Expense(); + e4.setId("4"); + e4.setName("Dining Spending"); + e4.setMoney("325"); + e4.setAccount("Cash"); + e4.setCreateTime("2016-06-18"); + e4.setDescription("Eat at TCU Cafe"); + + Expense e5 = new Expense(); + e5.setId("5"); + e5.setName("Stock Income"); + e5.setMoney("8000"); + e5.setAccount("WellsFargo Saving Account"); + e5.setCreateTime("2016-10-28"); + e5.setDescription("Apple Stock is great!"); + + Expense e6 = new Expense(); + e6.setId("6"); + e6.setName("Stock Income"); + e6.setMoney("5000"); + e6.setAccount("WellsFargo Saving Account"); + e6.setCreateTime("2016-10-28"); + e6.setDescription("Oracle Stock is great!"); + + Expense e7 = new Expense(); + e7.setId("7"); + e7.setName("Stock Income"); + e7.setMoney("3000"); + e7.setAccount("ChaseBank Saving Account"); + e7.setCreateTime("2016-10-28"); + e7.setDescription("Oct Salary time!"); + + Expense e8 = new Expense(); + e8.setId("8"); + e8.setName("Clothes Spending"); + e8.setMoney("5000"); + e8.setAccount("Cash"); + e8.setCreateTime("2016-10-28"); + e8.setDescription("JCrew again"); + + Expense e9 = new Expense(); + e9.setId("9"); + e9.setName("Other Spending"); + e9.setMoney("20"); + e9.setAccount("Cash"); + e9.setCreateTime("2016-10-29"); + e9.setDescription("Lost 20 bucks in library. :("); + + Expense e10 = new Expense(); + e10.setId("10"); + e10.setName("Gas Spending"); + e10.setMoney("1200"); + e10.setAccount("ChaseBank Credit Card"); + e10.setCreateTime("2016-10-29"); + e10.setDescription("Gas is so expensive"); + + Expense e11 = new Expense(); + e11.setId("11"); + e11.setName("Dining Spending"); + e11.setMoney("1000"); + e11.setAccount("ChaseBank Debit Card"); + e11.setCreateTime("2016-10-29"); + e11.setDescription("Eat eat eat"); + + Expense e12 = new Expense(); + e12.setId("12"); + e12.setName("Salary Income"); + e12.setMoney("3000"); + e12.setAccount("ChaseBank Saving Account"); + e12.setCreateTime("2016-10-30"); + e12.setDescription("Nov salary"); + + Expense e13 = new Expense(); + e13.setId("13"); + e13.setName("Flight Ticket Spending"); + e13.setMoney("500"); + e13.setAccount("ChaseBank Debit Card"); + e13.setCreateTime("2016-10-30"); + e13.setDescription("Fly to LA"); + + Expense e14 = new Expense(); + e14.setId("14"); + e14.setName("Salary Income"); + e14.setMoney("3000"); + e14.setAccount("ChaseBank Saving Account"); + e14.setCreateTime("2016-10-30"); + e14.setDescription("December Salary"); + + expenseDao.save(e1); + expenseDao.save(e2); + expenseDao.save(e3); + expenseDao.save(e4); + expenseDao.save(e5); + expenseDao.save(e6); + expenseDao.save(e7); + expenseDao.save(e8); + expenseDao.save(e9); + expenseDao.save(e10); + expenseDao.save(e11); + expenseDao.save(e12); + expenseDao.save(e13); + expenseDao.save(e14); + } +} diff --git a/src/main/java/edu/tcu/cs/expensetracker/domain/Expense.java b/src/main/java/edu/tcu/cs/expensetracker/domain/Expense.java new file mode 100644 index 0000000..9313a77 --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/domain/Expense.java @@ -0,0 +1,72 @@ +package edu.tcu.cs.expensetracker.domain; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import java.io.Serializable; +@Entity +public class Expense implements Serializable { + @Id + private String id; + private String name; + private String description; + private String money; + private String account; + private String createTime; + @ManyToOne + @JsonIgnore + private Expense owner; + + public Expense() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getMoney() { + return money; + } + + public void setMoney(String money) { + this.money = money; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/src/main/java/edu/tcu/cs/expensetracker/domain/Result.java b/src/main/java/edu/tcu/cs/expensetracker/domain/Result.java new file mode 100644 index 0000000..0fd2992 --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/domain/Result.java @@ -0,0 +1,60 @@ +package edu.tcu.cs.expensetracker.domain; + +/* +used to encapsulate data prepared by server side, this object will be serialized to JSON before +sent back to front end + */ +public class Result { + private boolean flag; //true: success, false: not success + private Integer code; //return status code. e.g. 200 + private String message; // message + private Object data; //return the requested data, in this case, a PageBean object + + public Result() { + } + + public Result(boolean flag, Integer code, String message) { + this.flag = flag; + this.code = code; + this.message = message; + } + + public Result(boolean flag, Integer code, String message, Object data) { + this.flag = flag; + this.code = code; + this.message = message; + this.data = data; + } + + public boolean isFlag() { + return flag; + } + + public void setFlag(boolean flag) { + this.flag = flag; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/src/main/java/edu/tcu/cs/expensetracker/domain/StatusCode.java b/src/main/java/edu/tcu/cs/expensetracker/domain/StatusCode.java new file mode 100644 index 0000000..f87ca6b --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/domain/StatusCode.java @@ -0,0 +1,10 @@ +package edu.tcu.cs.expensetracker.domain; + +public class StatusCode { + public static final int SUCCESS = 200; //Success + public static final int FAILURE = 400; //Failure + public static final int UNAUTHORIZED = 401; //username or password incorrect + public static final int FORBIDDEN = 403; //insufficent rights + public static final int NOT_FOUND = 404; //API not found + public static final int INTERNAL_SERVER_ERROR = 500;//Repetitive ops +} diff --git a/src/main/java/edu/tcu/cs/expensetracker/service/ExpenseService.java b/src/main/java/edu/tcu/cs/expensetracker/service/ExpenseService.java new file mode 100644 index 0000000..90b7d47 --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/service/ExpenseService.java @@ -0,0 +1,54 @@ +package edu.tcu.cs.expensetracker.service; + +import edu.tcu.cs.expensetracker.domain.Expense; +import edu.tcu.cs.expensetracker.dao.ExpenseDao; +import org.springframework.stereotype.Service; +import javax.transaction.Transactional; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@Transactional +public class ExpenseService { + + private ExpenseDao expenseDao; + + // Spring will automatically inject an instance of ExpenseDao + + public ExpenseService(ExpenseDao expenseDao) { + this.expenseDao = expenseDao; + } + + public List findAll(){ return expenseDao.findAll(); } + + public Expense findById(String expenseId) { return expenseDao.findById(expenseId).get(); } + + public List findBetweenDates(LocalDate startDate, LocalDate endDate) { + List dateList = startDate.datesUntil(endDate).collect(Collectors.toList()); + List startDates = expenseDao.findAll(); + List endDates = new ArrayList<>(); + + for (int i = 0; i < startDates.size(); i++) { + if (dateList.contains(LocalDate.parse(startDates.get(i).getCreateTime()))) { + endDates.add(startDates.get(i)); + } + } + return endDates; + } + + public void save(Expense newExpense) { + expenseDao.save(newExpense); + } + + public void update(String expenseId, Expense updatedExpense) { + updatedExpense.setId(expenseId); + expenseDao.save(updatedExpense); + } + + public void delete(String expenseId) { + expenseDao.deleteById(expenseId); + } +} diff --git a/src/main/java/edu/tcu/cs/expensetracker/utils/IdWorker.java b/src/main/java/edu/tcu/cs/expensetracker/utils/IdWorker.java new file mode 100644 index 0000000..bbca243 --- /dev/null +++ b/src/main/java/edu/tcu/cs/expensetracker/utils/IdWorker.java @@ -0,0 +1,104 @@ +package edu.tcu.cs.expensetracker.utils; + +import java.lang.management.ManagementFactory; +import java.net.InetAddress; +import java.net.NetworkInterface; + +public class IdWorker { + private final static long twepoch = 1288834974657L; + private final static long workerIdBits = 5L; + private final static long datacenterIdBits = 5L; + private final static long maxWorkerId = -1L ^ (-1L << workerIdBits); + private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); + private final static long sequenceBits = 12L; + private final static long workerIdShift = sequenceBits; + private final static long datacenterIdShift = sequenceBits + workerIdBits; + private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; + private final static long sequenceMask = -1L ^ (-1L << sequenceBits); + private static long lastTimestamp = -1L; + private long sequence = 0L; + private final long workerId; + private final long datacenterId; + + public IdWorker() { + this.datacenterId = getDatacenterId(maxDatacenterId); + this.workerId = getMaxWorkerId(datacenterId, maxWorkerId); + } + + public IdWorker(long workerId, long datacenterId) { + if (workerId > maxWorkerId || workerId < 0) { + throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); + } + if (datacenterId > maxDatacenterId || datacenterId < 0) { + throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); + } + this.workerId = workerId; + this.datacenterId = datacenterId; + } + + public synchronized long nextId() { + long timestamp = timeGen(); + if (timestamp < lastTimestamp) { + throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); + } + + if (lastTimestamp == timestamp) { + sequence = (sequence + 1) & sequenceMask; + if (sequence == 0) { + timestamp = tilNextMillis(lastTimestamp); + } + } else { + sequence = 0L; + } + lastTimestamp = timestamp; + long nextId = ((timestamp - twepoch) << timestampLeftShift) + | (datacenterId << datacenterIdShift) + | (workerId << workerIdShift) | sequence; + + return nextId; + } + + private long tilNextMillis(final long lastTimestamp) { + long timestamp = this.timeGen(); + while (timestamp <= lastTimestamp) { + timestamp = this.timeGen(); + } + return timestamp; + } + + private long timeGen() { + return System.currentTimeMillis(); + } + + protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) { + StringBuffer mpid = new StringBuffer(); + mpid.append(datacenterId); + String name = ManagementFactory.getRuntimeMXBean().getName(); + if (!name.isEmpty()) { + /* + * GET jvmPid + */ + mpid.append(name.split("@")[0]); + } + return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); + } + + protected static long getDatacenterId(long maxDatacenterId) { + long id = 0L; + try { + InetAddress ip = InetAddress.getLocalHost(); + NetworkInterface network = NetworkInterface.getByInetAddress(ip); + if (network == null) { + id = 1L; + } else { + byte[] mac = network.getHardwareAddress(); + id = ((0x000000FF & (long) mac[mac.length - 1]) + | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6; + id = id % (maxDatacenterId + 1); + } + } catch (Exception e) { + System.out.println(" getDatacenterId: " + e.getMessage()); + } + return id; + } +}