- Vue Js 3 + Quasar 2+ vue-quasar-example-app
- Vue Js 3 + Ionic 8 vue-ionic-example-app
Only supported on Java 1.8 and up, MySql 8 and up.
git clone https://github.com/bekaku/java-spring-boot-starter my-app
Repository will be downloaded into my-app/
folder
Database file located at my-app
/spring-data/files/spring_starter.sql and you can use following command for restore to your db.
$ mysql -uroot -p your_db_name < your_backup_file_path
example on windows
$ mysql -uroot -p your_db_name < E:\bak\db\spring_starter.sql
example on Ubuntu
$ mysql -uroot -p your_db_name < /var/tmp/spring_starter.sql
Config your database connection at my-app
/src/main/resources/application.yml
or application-dev.yml
datasource:
url: jdbc:mysql://${MYSQL_HOST:localhost}:3306/`your_db_name`?allowPublicKeyRetrieval=true&useSSL=false
username: `db_username`
password: `your_db_password`
Open Terminal and run following command
./gradlew bootRun
To test that it works, open a browser tab at http://localhost:8080/welcome
Build production jar and run following command jar location /build/libs/
./gradlew bootJar
Docker run
docker-compose build
docker-compose up -d
OpenAI, Swagger UI form API doc path
/api-docs, /swagger-ui/index.html
Server run at port 8080
can config server port at /src/main/resources/application.yml
server:
port: 8080
Change profiles active for development mode
spring:
profiles:
# active: prod
active: dev
Development mode properties config at /src/main/resources/application-dev.yml
app:
url: http://YOUR_SERVER_IP or http://127.0.0.1
port: 8080
cdn-directory: D:/code/tutorial/spring-data/ #your spring-data directory path
Log4j path config at resources/log4j2-dev.xml
and resources/log4j2-prod.xml
<Property name="APP_LOG_ROOT">D:/code/tutorial/spring-data/logs</Property>
Log4j path config at resources/log4j2-dev.xml
and resources/log4j2-prod.xml
<Property name="APP_LOG_ROOT">/usr/spring-data/logs</Property>
METHOD : POST
URL : /api/auth/login
Request Headers
Key | Value | Description |
---|---|---|
Content-Type | application/json;charset=utf-8 | |
Accept-Language | th | th, en |
Accept-ApiClient | default |
Request Parameters
Json root name : user
Key | Data type | Description |
---|---|---|
String | ||
password | String | |
loginForm | Int | Login From β 1 : web browser , 2 : iOS, 3 : Android |
{
"user": {
"emailOrUsername" : "[email protected]",
"password" : "P@ssw0rd",
"loginForm" : 1
}
}
Response success example π
{
"userId": 1,
"authenticationToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJmNGQxOGRlZi1hZTBjLTQ2MjItODE4OS1iNzExOTViNTkwNGYiLCJleHAiOjE3MzAxNjUwODYsImlhdCI6MTY5ODYyOTA4Nn0.hKun9E7D4rc-yEOA85Ex6rFYfWQww7ViOS9mpdIUn2Ql66JGCyxYf2vtqjbsQ-DSz8HB1lmVRSWtJ4XeBFkwCg",
"refreshToken": "f4d18def-ae0c-4622-8189-b71195b5904f",
"expiresAt": "2024-10-29T01:24:46.019+00:00"
}
Response fail example πΏ
{
"status": "UNAUTHORIZED",
"message": "Error",
"errors": [
"Login failed please verify that your username and password are correct."
],
"timestamp": "2021-05-04 17:19:32"
}
The header for the endpoint requires login verification.
Key | Value | Description |
---|---|---|
Content-Type | application/json;charset=utf-8 | |
Accept-Language | th | th, en |
Accept-ApiClient | default | |
Authorization | Bearer YOUR_authenticationToken |
Get current User
METHOD : GET
URL : /api/user/currentUserData
Response success example π
{
"id": 1,
"email": "[email protected]",
"username": "admin",
"token": null,
"fcmToken": null,
"accessTokenId": null,
"avatarFileId": null,
"coverFileId": null,
"avatar": {
"image": "http://127.0.0.1:8080/cdn/images/default-men-avatar.png",
"thumbnail": "http://127.0.0.1:8080/cdn/images/default-men-avatar.png"
},
"cover": null,
"active": true,
"selectedRoles": [
1
],
"defaultLocale": "th"
}
METHOD : GET
URL : /api/permission?page={currentPage}&size={size}&sort={#sortField,#sortType}
EXAMPLE : /api/permission?page=0&size=2&sort=code,asc
Request Parameter
Key | Data type | Description |
---|---|---|
page | Int | |
size | Int | |
sort | string,string | example createdDate,asc |
Response success example π
{
"dataList": [
{
"id": 2,
"code": "api_client_add",
"description": "api_client_list_add",
"module": "AD"
},
{
"id": 5,
"code": "api_client_delete",
"description": "api_client_delete",
"module": "AD"
}
],
"totalPages": 10,
"totalElements": 2,
"last": false
}
METHOD : POST
URL : /api/permission
Request Parameter
Json root name : permission
Key | Data type | Description |
---|---|---|
code | String | |
description | String | |
module | String |
Request example
{
"permission": {
"code": "read_report",
"description": "user can read report",
"module": "AD"
}
}
METHOD : PUT
URL : /api/permission
Request Parameter
Json root name : permission
Key | Data type | Description |
---|---|---|
id | Long | |
code | String | |
description | String | |
module | String |
Request example
{
"permision": {
"id": 2,
"code": "permission1",
"description": "permission1_detail",
"module": "app_user5"
}
}
METHOD : GET
URL : /api/permission/{id}
EXAMPLE : /api/permission/1
Response success example π
{
"id": 1,
"code": "api_client_list",
"description": "api_client_list",
"module": "AD"
}
METHOD : DELETE
URL : /api/permission/{id}
EXAMPLE : /api/permission/1
METHOD : GET
URL : /api/role?page={currentPage}&size={size}&sort={#sortField,#sortType}
EXAMPLE : /api/role?page=0&size=2&sort=code,asc
Request Parameter
Key | Data type | Description |
---|---|---|
page | Int | |
size | Int | |
sort | string,string | example createdDate,asc |
Response success example π
{
"dataList": [
{
"id": 1,
"name": "develop",
"description": "developer",
"status": true,
"selectdPermissions": null
}
],
"totalPages": 1,
"totalElements": 1,
"last": true
}
METHOD : POST
URL : /api/role
Request Parameter
Json root name : role
Key | Data type | Description |
---|---|---|
code | String | |
description | String | |
status | Boolean | |
selectdPermissions | Long[] |
Request example
{
"role": {
"name": "develop",
"description": "developer 555",
"status": true,
"selectdPermissions": [
1,
2,
3,
4
]
}
}
METHOD : PUT
URL : /api/role
Request Parameter
Json root name : permission
Key | Data type | Description |
---|---|---|
id | Long | |
code | String | |
description | String | |
status | Boolean | |
selectdPermissions | Long[] | |
Request example |
{
"role": {
"id": 55,
"name": "develop",
"description": "developer",
"status": true,
"selectdPermissions": [
1,
2
]
}
}
METHOD : GET
URL : /api/role/{id}
EXAMPLE : /api/role/1
Response success example π
{
"id": 1,
"name": "develop",
"description": "developer",
"status": true,
"selectdPermissions": null
}
METHOD : DELETE
URL : /api/role/{id}
EXAMPLE : /api/role/1
METHOD : POST
URL : /api/user
Request Parameter
Json root name : userRegister
Key | Data type | Description |
---|---|---|
String | unique | |
username | String | unique |
password | String | |
selectedRoles | Long[] |
{
"userRegister": {
"email": "[email protected]",
"username": "admin",
"password": "1234",
"selectedRoles": [
1,2
]
}
}
Response fail example πΏ
{
"status": "BAD_REQUEST",
"message": "Error",
"errors": [
"Username admin already exists. ",
"Email [email protected] already exists. "
],
"timestamp": "2021-05-05 09:02:24"
}
Access control list example usage
Just add an annotation @PreAuthorize("isHasPermission('{PERMISSION_NAME}||{PERMISSION_NAME2}||{PERMISSION_NAME3}')")
to method in controller.
package com.bekaku.api.spring.controller.api;
@RequestMapping(path = "/api/role")
@RestController
@RequiredArgsConstructor
public class RoleController extends BaseApiController {
private final RoleService roleService;
private final PermissionService permissionService;
private final I18n i18n;
private final RoleValidator roleValidator;
Logger logger = LoggerFactory.getLogger(RoleController.class);
@Value("${app.loging.enable}")
boolean logEnable;
@PreAuthorize("isHasPermission('role_list')")
@GetMapping
public ResponseEntity<Object> findAll(Pageable pageable) {
logger.info("/api/role > findAll, isLogEnable {}", logEnable);
return this.responseEntity(roleService.findAllWithPaging(!pageable.getSort().isEmpty() ? pageable :
PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Role.getSort())), HttpStatus.OK);
}
@PreAuthorize("isHasPermission('role_add||user_manage')")
@PostMapping
public ResponseEntity<Object> create(@Valid @RequestBody RoleDto dto) {
Role role = roleService.convertDtoToEntity(dto);
roleValidator.validate(role);
setRolePermission(dto, role);
roleService.save(role);
return this.responseEntity(roleService.convertEntityToDto(role), HttpStatus.CREATED);
}
private void setRolePermission(RoleDto dto, Role role) {
if (dto.getSelectdPermissions().length > 0) {
Optional<Permission> permission;
for (long permissionId : dto.getSelectdPermissions()) {
permission = permissionService.findById(permissionId);
permission.ifPresent(value -> role.getPermissions().add(value));
}
}
}
}
Access is denied response example πΏ
{
"status": "INTERNAL_SERVER_ERROR",
"message": "Access is denied",
"errors": [
"error occurred"
],
"timestamp": "2021-05-05 09:03:45"
}
Add an annotation @GenSourceableTable
to indicate that you want to create Auto source.
package com.bekaku.api.spring.model;
import annotation.com.bekaku.api.spring.GenSourceableTable;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.domain.Sort;
import jakarta.persistence.*;
@GenSourceableTable
@NoArgsConstructor
@Getter
@Setter
@Entity
public class Role extends BaseEntity {
@Column(name = "name", length = 100, nullable = false, unique = true)
private String name;
@Column(name = "description", columnDefinition = "text default null")
private String description;
@Column(name = "status", columnDefinition = "tinyint(1) default 1")
private Boolean status;
public static Sort getSort() {
return Sort.by(Sort.Direction.ASC, "name");
}
}
Call http://localhost:{your_server_port}/dev/development/generateSrc
to auto generate source
METHOD : POST
URL : dev/development/generateSrc
The system will generate the following files.
RoleDto
dto PackageRoleRepository
repository PackageRoleService
service PackageRoleServiceImpl
serviceImpl PackageRoleController
api.controller Package
If you use my vue-quasar-example-app You can create frontend List.vue and Form.vue by adding additional annotaion 'createFrontend = true' Call http://localhost:{your_server_port}/dev/development/generateSrc
to auto generate source
It will be created at build\generated\frontend
@GenSourceableTable(createFrontend = true)
public class Role extends BaseEntity {
}