Feb 1997

Overtime and overdue


  • Home

  • Tags

  • Categories

  • Archives

  • Search

Spring Boot: Unified Response Body

Posted on 2020-08-25 Edited on 2020-08-26

Introduction

Front and rear separation is very popular nowadays, so how to design a good RESTful API and how to enable front end programmers to handle standard response JSON data structure are significant. In order for the front end to have a better logical display and page interaction processing, every RESTful request should contain the following information:
| Name | Description |
| —— | —— |
| status | Indicate the request success or not |
| errorCode | Give a specific error code to match the service exception |
| errorMsg | More specific error message |
| resultBody | Result, usually Bean object in JSON format |
Note: As for the resultBody, usually we declare it as Generic Class to adapt different return type.

Implementation

Define the generic return class

According to the form above, the Java Bean code would be like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Data
public final class CommonResult<T> {

private int status = 1;

private String errorCode = "";

private String errorMsg = "";

private T resultBody;

public CommonResult() {
}

public CommonResult(T resultBody) {
this.resultBody = resultBody;
}
}

Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@EnableWebMvc
@Configuration
public class UnifiedReturnConfig {

@RestControllerAdvice("com.example.unifiedreturn.api")
static class CommonResultResponseAdvice implements ResponseBodyAdvice<Object>{
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
return true;
}

@Override
public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (body instanceof CommonResult){
return body;
}

return new CommonResult<Object>(body);
}
}
}

In this step, we create a static class CommonResultResponseAdvice which implementes interface ResponseBodyAdvice<Object>. By doing this, the response body will be intercepted and we override the method beforeBodyWrite() which can do conversion between body and our customized CommonResult.

Spring Security: Define secured URLS dynamically

Posted on 2020-08-17 Edited on 2020-08-25

After browsing the official document of Spring Security, I found there is no such a solution to help with dynamically configure url authorization. By default, Spring Security will initialize the url authorization as the applilcation starts.

There is a question in the document 44.4.6. How do I define the secured URLs within an application dynamically?. After reading the solution to this problem, I draw a solution with two steps:

  1. Provide data which describes the rules of access.
    SecurityMetadataSource obtains the metadata for a particular method or filter invocation
  2. Customize an interceptor and add it into the Spring Security’s filterChain.

Authorization Datasource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* Config authentication data source to implement dynamically authorization load
*/
@Component
public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
// Authorization data
private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;

/**
* Find the authorization data according to current url in the initial authorization datasource
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
FilterInvocation fi = (FilterInvocation) object;
HttpServletRequest request = fi.getRequest();

// traverse the initialized authorization data and find authorization according to current url
for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap
.entrySet()) {
if (entry.getKey().matches(request)) {
return entry.getValue();
}
}
return null;
}

@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}

@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}

/**
* Update authorization collection
*/
public void setRequestMap(List<SysAuthorityVo> authorityVoList){
Map<RequestMatcher, Collection<ConfigAttribute>> map = new ConcurrentHashMap<>();
for (SysAuthorityVo sysAuthorityVo : authorityVoList) {
String authorityName = sysAuthorityVo.getAuthorityName();
if (StringUtils.isEmpty(sysAuthorityVo.getAuthorityContent())) continue;
for (String url : sysAuthorityVo.getAuthorityContent().split(",")) {
Collection<ConfigAttribute> value = map.get(new AntPathRequestMatcher(url));
if (StringUtils.isEmpty(value)) {
ArrayList<ConfigAttribute> configs = new ArrayList<>();
configs.add(new SecurityConfig(authorityName));
map.put(new AntPathRequestMatcher(url), configs);
} else {
value.add(new SecurityConfig(authorityName));
}
}
}
this.requestMap = map;
}
}

Customize Dynamically Url Interceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
* Customize DynamicallyUrlInterceptor
*/
public class DynamicallyUrlInterceptor extends AbstractSecurityInterceptor implements Filter {

// label customized url interceptor has already been loaded
private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied_dynamically";

private FilterInvocationSecurityMetadataSource securityMetadataSource;
private boolean observeOncePerRequest = true;


@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@Override
public void destroy() {
}

public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return this.securityMetadataSource;
}

public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}

public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
this.securityMetadataSource = newSource;
}

@Override
public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
super.setAccessDecisionManager(accessDecisionManager);
}

public void invoke(FilterInvocation fi) throws IOException, ServletException {

if ((fi.getRequest() != null)
&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
&& observeOncePerRequest) {
// filter already applied to this request and user wants us to observe
// once-per-request handling, so don't re-do security checking
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
else {
// first time this request being called, so perform security checking
if (fi.getRequest() != null) {
fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
}

InterceptorStatusToken token = super.beforeInvocation(fi);

try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
}
finally {
super.finallyInvocation(token);
}

super.afterInvocation(token, null);
}
}
}

Decision Manager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* Decision Manager
*/
public class MyAccessDecisionManager extends AbstractAccessDecisionManager {

MyAccessDecisionManager(List<AccessDecisionVoter<?>> decisionVoters) {
super(decisionVoters);
}

@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
int deny = 0;

for (AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, configAttributes);

if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}

switch (result) {
case AccessDecisionVoter.ACCESS_GRANTED:
return;

case AccessDecisionVoter.ACCESS_DENIED:
deny++;

break;

default:
break;
}
}

if (deny > 0) {
throw new AccessDeniedException(messages.getMessage(
"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
}

// To get this far, every AccessDecisionVoter abstained
checkAllowIfAllAbstainDecisions();
}
}

Spring Security provided several authorization strategy, here we are using RoleVoter.

Configure filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    //filter
@Bean
public DynamicallyUrlInterceptor dynamicallyUrlInterceptor(){
// Retrieve the datasource
List<SysAuthorityVo> authorityVoList = sysAuthorityService.list(new SysAuthorityVo()).getData();
myFilterInvocationSecurityMetadataSource.setRequestMap(authorityVoList);
// Initialize interceptor and load the datasource
DynamicallyUrlInterceptor interceptor = new DynamicallyUrlInterceptor();
interceptor.setSecurityMetadataSource(myFilterInvocationSecurityMetadataSource);

// Configure RoleVoter Strategy
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
decisionVoters.add(new RoleVoter());

// Set Access Decision Manager
interceptor.setAccessDecisionManager(new MyAccessDecisionManager(decisionVoters));
return interceptor;
}
}

Add filter into Spring Security’s Filter

1
2
3
4
5
6
7
8
9
10
11
12
http
// customize the url access authority and read the authentication dynamically

.addFilterAfter(dynamicallyUrlInterceptor(), FilterSecurityInterceptor.class)
.authorizeRequests()

// permit all which means no limitation against authority
.antMatchers("/favicon.ico","/common/**", "/webjars/**", "/getVerifyCodeImage","/error/*").permitAll()

// other interfaces are accessible only after login
.anyRequest().authenticated()
.and();

AWS: OCR application based on Lambda

Posted on 2020-08-09 Edited on 2020-08-17

Project Description

This project utilizes Lambda and Rekognition to build an OCR application which can extract text information from the image.

Environment

  • Operating System: Windows 10 (Home Edition)
  • Tools:
    • CMD with administrator privileges
    • Docker Desktop
    • AWS SAM CLI
  • Language: Python 3.6

Preparation

  1. Build Python virtual environment
    One of the advantages of Python is rich libs. However, in order to avoid redundant libs and manage the project easily, we use virtual environment.

    1
    python -m venv ~/.venvs/aws_sam
  2. Use virtual environment
    First entering Scripts folder, then run the activate.bat to use the virtual environment

    1
    2
    cd C:\Windows\System32\~\.venvs\aws_sam\Scripts
    activate.bat

    Once the result looks like:
    (aws_sam) C:\Windows\System32\~\.venvs\aws_sam\Scripts>
    we have already start the virtual environment aws_sam

  3. Update environment

    1
    pip3 install pip setuptools wheel
  4. Install packages
    Since we are using virtual environment, we only have two packages, pip and setuptools. So we need to install packages.

    1
    2
    3
    pip3 install boto3 botocore -U
    pip3 install awscli -U
    pip3 install aws-sam-cli -U
    • boto3: Boto is the Amazon Web Services (AWS) SDK for Python. It enables Python developers to create, configure, and manage AWS services, such as EC2 and S3. Boto provides an easy to use, object-oriented API, as well as low-level access to AWS services.
    • botocore: Botocore is a low-level interface to a growing number of Amazon Web Services. Botocore serves as the foundation for the AWS-CLI command line utilities. It will also play an important role in the boto3.x project.
    • awscli: The AWS Command Line Interface (CLI) is a unified tool to manage your AWS services. With just one tool to download and configure, you can control multiple AWS services from the command line and automate them through scripts.
    • aws-sam-cli: Use this tool to build serverless applications that are defined by AWS SAM templates. The CLI provides commands that enable you to verify that AWS SAM template files are written according to the specification, invoke Lambda functions locally, step-through debug Lambda functions, package and deploy serverless applications to the AWS Cloud, and so on.

Build project

  1. Download code from Github

    1
    sam init git@github.com:xiaokeliu666/AWS_OCR.git
  2. Build project

    1
    sam build

Deploy

  1. Package local environment
    Since the environment of Lambda is too complicated to simulate locally, here we use docker container to build the project. In Docker-hub, there is already an image of docker-lambda)

    1
    sam build --use-container
  2. Create an S3 bucket

    1
    aws s3 mb s3://my-lambda-ocr-repo
  3. Package

    1
    sam package --template-file template.yaml --output-template-file packaged.yaml --s3-bucket my-lambda-ocr-repo

After excuting, a configuration file will be created in S3 bucket.

  1. Deploy to Lambda

    1
    sam deploy --template-file packaged.yaml --stack-name aws-sam-ocr --capabilities CAPABILITY_IAM --region us-east-1

    In this step, CloudFormation is used to build (template.yaml), so stack name is required. By excuting this step, we will create: table of dynamoDB, S3 bucket and Lambda function.
    We can monitor the process of deployment in AWS -> CloudFormation -> Stacks

Test

  1. Upload picture to bucket
    First, we prepare a folder called “pic” to store pictures
    There are two buckets relative to this project. The first one is which we upload file to and the second one is where stored the configuration file.

    So, we upload picture to the first bucket

    1
    aws s3 cp pic/news.jpg s3://aws-lambda-ocr-sourceimagebucket-dqrx1qpra9wr
  2. Find the result in dynamoDB
    news.jpg:

    Result:

AWS: Lambda

Posted on 2020-08-09

Before diving into Lambda, a new concept, Serverless Computing, should be introduced.

Serverless Computing

Serverless computing is a cloud computing execution model in which the cloud provider runs the server, and dynamically manages the allocation of machine resources. Pricing is based on the actual amount of resources consumed by an application, rather than on pre-purchased units of capacity. It can be a form of utility computing.

Serverless computing can simplify the process of deploying code into production. Scaling, capacity planning and maintenance operations may be hidden from the developer or operator. Serverless code can be used in conjunction with code deployed in traditional styles, such as microservices. Alternatively, applications can be written to be purely serverless and use no provisioned servers at all.

Why AWS Lambda

Amazon EC2

  • Virtual Servers in the Cloud
  • Limited by RAM and CPU
  • Continuously running
  • Scaling means intervention to add / remove servers

    Amazon Lambda

  • Virtual functions - no servers to manage
  • Limited by time - short executions
  • Run on-demand
  • Scaling is automated

    Benefits of AWS Lambda

  • Easy pricing
  • Integrated with the whole AWS suite of services
  • Event-Driven: functions get invoked by AWS when needed
  • Integrated with many programming language
  • Easy monitoring through AWS CloudWatch
  • Easy to get more resources per functions(up to 3GB of RAM)
  • Increasing RAM will also improve CPU and network

AWS: S3

Posted on 2020-08-09

S3 is advertised as infinitely scaling storage

S3 Use Cases

  • Backup and storage
  • Disaster Recovery
  • Archive
  • Hybrid Cloud storage
  • Application hosting
  • Media hosting
  • Data lakes & big data analytics
  • Software delivery
  • Static website

Buckets

  • Amazon S3 allows people to store objects(files) in “buckets” (directories)
  • Buckets must have a globally unique name (across all regions all accounts)
  • Buckets are defined at the region level
  • S3 looks like a global service but buckets are created in a region
  • Objects(Files) have a key. The key is the full path:
    • s3://my-bucket/my_file.txt
    • s3://my-bucket/my_folder/anoter_folder/my_file.txt
  • There’s no concept of “directories” within buckets

    Buckets Policies

  • JSON based policies
    • Resources: buckets and objects
    • Actions: Set of API to Allow or Deny
    • Effect: Allow / Deny
    • Principal: The account or user to apply the policy to
      Example:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Sid": "PublicRead",
      "Effect": "Allow",
      "Principal": "*",
      "Action": [
      "s3:GetObject"
      ],
      "Resource": [
      "arn:aws:s3:::examplebucket/*"
      ]
      }
      ]
      }

AWS: EC2

Posted on 2020-08-09

EC2

  • EC2 = Elastic Compute Cloud = Infrastructure as a Service
  • It mainly consists in the capability of :
    • Renting virtual machines (EC2)
    • Storing data on virtual drives (EBS)
    • Distributing load across machines (ELB)
    • Scaling the services using an auto-scaling group (ASG)

EC2 sizing & confituration options

  • Operating System: Linux or Windows
  • CPU
  • RAM
  • Storage space
    • network-attached (EBS & EFS)
    • hardware (EC2 Instance Store)
  • Network card: speed of the card, Public IP address
  • Firewall rules: security group
  • Bootstrap script (configure at first launch): EC2 User Data

Security Groups

  • Security groups control how traffic is allowed into or out of our EC2 Instances
  • Security groups only contain allow rules
  • Security groups rules can refernce by IP or by security group
  • Security groups regulate:
    • Access to Ports
    • Authorised IP ranges - IPv4 and IPv6
    • Control of inbound network (from other to the instance)
    • Control of outbound network (from the instance to other)

Classic Ports

  • 22 = SSH (Secure Shell) - log into a Linux instance
  • 21 = FTP (File Transport Protocol) - upload files into a file share
  • 22 = SFTP (Secure File Transport Protocol) - upload files using SSH
  • 80 = HTTP - access unsecured websites
  • 443 = HTTPS - access secured websites
  • 3389 = RDP (Remote Desktop Protocol) - log into a Windows instance

Docker: Install on Windows10 (Home edition)

Posted on 2020-08-08 Edited on 2020-08-09

During the process of developing my OCR application on AWS, I needed to use container to build my project. However, Docker doesn’t support Windows10 (Home edition) perfectly. Using Docker toolbox can be a solution but I failed. So, I take this note to record the steps and mistakes I made to install Docker Desktop.

Steps

  1. Generate a file hyperv.cmd:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    pushd "%~dp0"

    dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt

    for /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"

    del hyper-v.txt

    Dism /online /enable-feature /featurename:Microsoft-Hyper-V-All /LimitAccess /ALL
  2. Run hyperv.cmd with administrator privileges and restart may be required.

  3. Turn on Windows features Hyper-V (Control Panel: Turn Windows features on or off)
  4. “Change” the edition of Windows
    Here we don’t really change the edition, we just change the value in registery. Run Command Line with administrator privileges:
    REG ADD "HKEY_LOCAL_MACHINE\software\Microsoft\Windows NT\CurrentVersion" /v EditionId /T REG_EXPAND_SZ /d Professional /F
  5. Download Docker on https://store.docker.com/editions/community/docker-ce-desktop-windows

Mistake

Q. “Error with docker-compose: docker-credential-desktop not installed or not available in PATH”
A. There is an typo in the ~/.docker/config.json:”credSstore” instead of “credsStore”. This is not an issue only happens to me because I found the solution on Github. Obviously, this typo exists not only Windows but also MacOS

AWS: Traditional IT vs Cloud Computing

Posted on 2020-08-08

What is a server composed of?

  • Compute: CPU
  • Memory: RAM
  • Storage: Data
  • Database: Store data in a structured way
  • Network: Routers, switch, DNS server
    • Network: cables, routers and servers connected with each other
    • Router: A networking device that forwards data packets between computer networks. They know where to send your packets on the internet
    • Switch: Takes a packet and send it to the correct server / client on your network

Problems with traditional IT approach

  • Pay for the rent for the data center
  • Pay for the power supply, cooling, maintenance
  • Adding and replacing hardware takes time
  • Scaling is limited
  • Hire 24/7 team to monitor the infrastructure
  • How to deal with disasters? (earthquake, power shutdown, fire…)

What is Cloud Computing?

  • Cloud computing is the on-demand delivery of computer power, datebase storage, applications, and other IT resources
  • Through a cloud services platform with pay-as-you-go pricing
  • You can provision exactly the right type and size of computing resources you need
  • You can access as many resources as you need, almost instantly
  • Simple way to access servers, storage, databases and a set of application services
  • Amazon Web Services owns and maintains the network-connected hardware required for these application services, while you provision and use what you need via a web application.

Five Characteristics of Cloud Computing

  • On-demand self service:
    • Users can provision resources and use them without human interaction from the service provider
  • Broad network access:
    • Resources available over the network, and can be accessed by diverse client platforms
  • Multi-tenancy and resource pooling:
    • Multiple customers can share the same infrastructure and applications with security and privacy
    • Multiple customers are served from the same physical resources
  • Rapid elasticity and scalability:
    • Automatically and quickly acquire and dispose resources when needed
    • Quickly and easily scale based on demand
  • Measured service:
    • Usage is measured, users pay correctly for what they have used

Six Advantages of Cloud Computing

  • Trade capital expense(CAPEX) for operational expense(OPEX)
    • Pay On-Demand: don’t own hardware
    • Reduced Total Cost of Ownership(TCO) & Operational Expense(OPEX)
  • Benefit from massive economies of scale
    • Prices are reduced as AWS is more efficient due to large scale
  • Stop guessing capacity
    • Scale based on actual measured usage
  • Increase speed and agility
  • Stop spending money running and maintaining data centers
  • Go global in minutes: leverage the AWS global infrastructure

Type of Cloud Computing

  • Infrastructure as a Service (IaaS)
    • Provides building blocks for cloud IT
    • Provides networking, computers, data storage space
    • Highest level of flexibility
    • Easy parallel with traditional on-premises IT
  • Platform as a Service (PaaS)
    • Removes the need for your organization to manage the underlying infrastructure
    • Focus on the deployment and management of your applications
  • Software as a Service (SaaS)
    • Completed product that is run and managed by the service provider

A secure scheme for data exchange: AES + RSA

Posted on 2020-08-03 Edited on 2020-08-04

AES

The algorithm described by AES is a symmetric-key algorithm, meaning the same key is used for both encrypting and decrypting the data.

Symmetric encryption is a type of encryption where only one key (a secret key) is used to both encrypt and decrypt electronic information. The entities communicating via symmetric encryption must exchange the key so that it can be used in the decryption process.

RSA

Asymmetric Encryption is a form of Encryption where keys come in pairs. What one key encrypts, only the other can decrypt. Frequently (but not necessarily), the keys are interchangeable, in the sense that if key A encrypts a message, then B can decrypt it, and if key B encrypts a message, then key A can decrypt it.

Hybrid Cryptosystem

Interface data encyrption

Steps:

  1. Client starts and sends request to server.
  2. Server generates a pair of keys(pubKey1 and priKey1) with RSA.
  3. Server sends pubKey1 back to client.
  4. Client generates a pair of keys(pubKey2 and priKey2) with RSA.
  5. Client encrypts pubKey2 with pubKey1.
  6. Client sends pubKey2 back to server.
  7. Server decrypts the ciphertext with priKey1 to get pubKey2. (Because the ciphertext is encrypted by pubKey1)
  8. Server generates symmetric encryption whose length is 16 with AES.
  9. Server encrypts the AES key with pubKey2 and sends to client.
  10. Client decrypts the AES key with priKey2 to get AES key.
  11. Finally, using encrypted key to do the encryption of data transmision.

Note:

  1. RSA is asymmetric encryption: public key encrypts while private key decrypts.
  2. AES is symmetric encryption: the same key is used for both encrypting and decrypting the data.
  3. Since there is a limitation against size when using RSA, so segmentation is required.
  4. Use the public key of RSA to encrypt AES, then use AES to decrypt/encrypt the content.

Spring REST 6: CRUD

Posted on 2020-07-27

Annotations

@RestController

The @RestController annotation was introduced in Spring 4.0 to simplify the creation of RESTful web services. It’s a convenience annotation that combines @Controller and @ResponseBody – which eliminates the need to annotate every request handling method of the controller class with the @ResponseBody annotation.

@PathVariable

While @RequestParams extract values from the query string, @PathVariables extract values from the URI path:

1
2
3
4
5
@GetMapping("/foos/{id}")
@ResponseBody
public String getFooById(@PathVariable String id) {
return "ID: " + id;
}

For @PathVariable, we map on path:

1
2
3
http://localhost:8080/foos/abc
----
ID: abc

1
2
3
4
5
@GetMapping("/foos")
@ResponseBody
public String getFooByIdUsingQueryParam(@RequestParam String id) {
return "ID: " + id;
}

For @RequestParam, we map on path:

1
2
3
http://localhost:8080/foos?id=abc
----
ID: abc

@RequestBody

Simply put, the @RequestBody annotation maps the HttpRequest body to a transfer or domain object, enabling automatic deserialization of the inbound HttpRequest body onto a Java object.

CRUD

POST

1
2
3
4
5
6
7
    @PostMapping("/saveCustomer")
public Customer saveCustomer(@RequestBody Customer theCustomer) {
// save the customer using our service
theCustomer.setId(0);
customerService.saveCustomer(theCustomer);
return theCustomer;
}

GET

1
2
3
4
5
6
@GetMapping("/search/{theSearchName}")
public List<Customer> search(@PathVariable String theSearchName) {
// search customers from the service
List<Customer> theCustomers = customerService.searchCustomers(theSearchName);
return theCustomers;
}

DELETE

1
2
3
4
5
6
    @DeleteMapping("/delete/{customerId}")
public String delete(@PathVariable int customerId) {
// Customer tempCustomer = customerService.getCustomer(customerId);
customerService.delete(customerId);
return "Delete customer id:" + customerId;
}

PUT

1
2
3
4
5
@PutMapping("/updateCustomer")
public Customer updateCustomer(@RequestBody Customer theCustomer) {
customerService.saveCustomer(theCustomer);
return theCustomer;
}

Test

For get/delete testing, just input the uri and select the right method.
For put/post testing, besides the steps above:

  • Select ‘Body’
  • Select ‘raw’
  • Select ‘JSON’
  • Input data in JSON fashion
  • Send request
12…12
Feb 1997

Feb 1997

112 posts
4 categories
24 tags
© 2020 Feb 1997