From 8f71e4c7710e87b8e30882820752bc415599c026 Mon Sep 17 00:00:00 2001 From: "LAPTOP-MN70S2TH\\2fiadmin" Date: Mon, 6 Feb 2023 14:11:20 +0800 Subject: [PATCH] first commit --- README.md | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c9a2463 --- /dev/null +++ b/README.md @@ -0,0 +1,166 @@ +### frontend: + - Routes.js (path: 'xxx**Win**' for Window component) + - load js resources: + ```javascript + // option 1 + items: [ + Ext.create('App.test.TestPanel',{ + title: 'Title 1' + }), + { + xtype: 'panel', + title: 'Title 2' + } + ] + + // option 2 + requires: ['App.xxxx.XxxxPanel'], + items: [{ + xtype: 'test.testPanel', + title: 'Title 1' + }] + ``` + - get component e.g. + ```javascript + me.down('test\\.testPanel') //alias: 'widget.test.testPanel' + - i18n: static/public/i18n/{locale}.json + ```javascript + // component level + bind: { + text: '{i18n.xx.xx}' + } + // program level + App.getI18n('xx.xx') // or App.getI18n().xx.xx + - security + - App.security.getUser() + - App.security.isGranted(string | string[]) + - App.security.isGrantedAll(string[]) + +### backend (draft): + - vs code dev: example.launch.json + - db migration: resources/db/changelog/changes/\*\* (support subfolder) + - suggested that one changeset with one DDL + - filename: {yyyyMMdd}\_{number}\_{name}/{number}_{name}.sql + - filename 2(optional): {yyyyMMdd}\_{number}\_{name}/{number}\_{name}/{number}\_{name}.sql + ```sql + --liquibase formatted sql + + --changeset {name}:{id} + --comment: remarks (optional) + CREATE TABLE `tableName` ( + `id` INT PRIMARY KEY AUTO_INCREMENT, + `created` DATETIME NOT NULL DEFAULT NOW(), + `createdBy` VARCHAR(30), + `version` INT NOT NULL DEFAULT 0, + `modified` DATETIME NOT NULL DEFAULT NOW(), + `modifiedBy` VARCHAR(30), + `deleted` BOOLEAN NOT NULL DEFAULT FALSE, + + `column1` INT NOT NULL, + `column2` VARCHAR(255) + ); + ``` + - controller + - AbstractController + - api: /public/\*\* /protected/\*\* + - RequestBody Class (`@NotNull`, `@NotBlank`, `@Min`, `@Max`, `@Pattern`, etc...) + ```java + @NotNull + @Pattern(regexp = "^Y$|^N$") + private String YesNo; + ``` + - authentication check: `@PreAuthorize` + - common response class `DataRes`, `IdRes`, `RecrodsRes`, `SuccessRes` + - RESTfull api (http method, http status) + - http status: + - 404: record not found + - 409: record_line not found or record_line not under the record (relation check) + - 422: something wrong, (e.g. qty not enough) + - suggest /save api (also allowed for POST: new, PUT: update) + 1. POST /xxxx/save + 2. body: + ```json + { + "id": 1, //update + "xx": "xx", + "updateLines": [ + { + "id": null, // new + "xx": "xx" + }, + { + // need a relation check + "id": 1, //update + "xx": "xx" + } + ], + // need a relation check + "deleteLineIds": [1, 2] + } + ``` + ```java + //example + @RestController + @RequestMapping("/xxxx") + public class ExampleController extends AbstractController { + + @PostMapping('/xxx') // @GetMapping @DeleteMapping @PutMapping @PatchMapping + //@ResponseStatus(HttpStatus.CREATED) + //@PreAuthorize("hasAuthority('XXX_MAINT')") + public Xxxx api (@RequestBody @Valid ReqClass req) { + } + + @GetMapping('/{id}') + public Xxxx getXxx (@PathVariable int id) { + } + } + ``` + - service + - AbstractService, AbstractIdEntityService, AbstractBaseEntityService + - `@Transactional(rollbackFor = Exception.class)` for write, read only not need transaction + - dao + - interface + - AbstractDao + - [Query Creation](https://docs.spring.io/spring-data/jpa/docs/2.7.0/reference/html/#jpa.query-methods.query-creation) + - `@Query` + ```java + public Optional findByUsernameAndDeletedFalse(String username); + // same + @Query("FROM #{#entityName} u WHERE u.deleted = FALSE AND u.username = :username") + public Optional findByUsername(@Param("username") String username); + ``` + - entity + - IdEntity, BaseEntity + - validation: `@NotNull`, `@NotBlank`, `@Min`, `@Max`, `@Pattern`, etc... + - jdbcDao + - reduce Map: queryForEntity, queryForList("SELECT xxx" , params, XxxRecord.class) + - [Class Object vs Hashmap](https://stackoverflow.com/questions/10258071/class-object-vs-hashmap) + - reduce `@Autowired` + - use constructor + - try separate class (e.g. FileListController, FileDownloadController) + - return Optional instead of null + - return Optional\ : may null + - return T : must not null + - i18n: i18n/messages_{locale(underscore)}.properties + - `messageSource.getMessage("name", null, LocaleUtils.getLocale());` + - reporting: + - excel: + - files: + - excel/{filename}.xlsx + - excel/{filename}_zh-TW.xlsx + - excel/{filename}_zh-CN.xlsx + - load Workbook: `ExcelUtils.loadTemplate("excel/{filename}");` + - send out Workbook: `ExcelUtils.send(response, workbook, "filename"); // will output filename.xlsx` + - jasper + - files: + - reports/{filename}.jrxml + - reports/{filename}_zh-TW.jrxml + - reports/{filename}_zh-CN.jrxml + - compile: `JasperUtils.compile("reports/{filename}", params, new JRBeanCollectionDataSource(xxx), Map.of("subReport1","reports/{filename}"));` + - send out: `JasperUtils.responsePdf(response, jRerpot, "filename"); // will output filename.pdf` + - mobile: + - login: POST /mobile/login + - logout: POST /mobile/logout + - call api: http headers with + 1. `X-ATT-DeviceId` + 2. `X-ATT-Access-Token` \ No newline at end of file