Wednesday, December 10, 2025

Spring Boot web app with MYSQL integration

 

1) Spring Boot (with REST & MySQL JPA)

Project type: Spring Boot (Maven).
Java version: 11+ recommended.

pom.xml (essential deps)

<project ...>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>profitloss-service</artifactId>
  <version>1.0.0</version>

  <properties>
    <java.version>11</java.version>
    <spring.boot.version>3.1.0
</spring.boot.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot
</groupId>
      <artifactId>spring-boot-starter-web
</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot
</groupId>
      <artifactId>spring-boot-
starter-data-jpa</artifactId>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-
java</artifactId>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.
boot</groupId>
      <artifactId>spring-boot-
starter-validation</artifactId>
    </dependency>
    
    <dependency>
      <groupId>com.fasterxml.
jackson.core</groupId>
      <artifactId>jackson-
databind</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.
boot</groupId>
        <artifactId>spring-boot-
maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

src/main/resources/application.properties

Replace username/password/dbname with your MySQL values.

spring.datasource.url=jdbc:mysql:
//localhost:3306/profitlossdb?useSSL=
false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=yourpassword

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.
format_sql=true

server.port=8080

Domain: com.example.profitloss.model.Calculation.java

package com.example.profitloss.model;

import jakarta.persistence.*;
import java.time.Instant;

@Entity
public class Calculation {

    @Id
    @GeneratedValue(strategy =
 GenerationType.IDENTITY)
    private Long id;

    private double cp;
    private double sp;
    private double amount; // 
profit or loss magnitude
    private double percent;
    private boolean isProfit;
 // true -> profit, false -> 
loss (if equal, treat as neither)
    private Instant createdAt =
 Instant.now();

    // Constructors, getters, setters
    public Calculation() {}
    public Calculation(double cp,
 double sp, double amount, 
double percent, boolean isProfit) {
        this.cp = cp; this.sp = 
sp; this.amount = amount;
 this.percent = percent; this.isProfit = isProfit;
    }
    // getters and setters
 omitted for brevity (generate in IDE)
    // ...
    public Long getId(){return id;}
    public double getCp(){return cp;}
    public void setCp(double cp){this.cp=cp;}
    public double getSp(){return sp;}
    public void setSp(double sp){this.sp=sp;}
    public double getAmount(){return amount;}
    public void setAmount(double amt)
{this.amount=amt;}
    public double getPercent()
{return percent;}
    public void setPercent(double p)
{this.percent=p;}
    public boolean isProfit()
{return isProfit;}
    public void setProfit
(boolean profit){this.isProfit=profit;}
    public Instant getCreatedAt()
{return createdAt;}
    public void setCreatedAt
(Instant t){this.createdAt=t;}
}

Repository: CalculationRepository.java

package com.example.profitloss.repo;

import com.example.profitloss.
model.Calculation;
import org.springframework.data.
jpa.repository.JpaRepository;

public interface CalculationRepository 
extends JpaRepository<Calculation, Long> {}

DTO: CalculateRequest.java

package com.example.profitloss.dto;

import jakarta.validation.constraints.Min;

public class CalculateRequest {
    @Min(value = 0, message = 
"Cost price must be >= 0")
    private double cp;

    @Min(value = 0, message =
 "Selling price must be >= 0")
    private double sp;

    public double getCp(){return cp;}
    public void setCp(double cp){this.cp=cp;}
    public double getSp(){return sp;}
    public void setSp(double sp){this.sp=sp;}
}

Response DTO: CalculateResponse.java

package com.example.profitloss.dto;

public class CalculateResponse {
    private String type; // "profit",
"loss","no-profit-no-loss"
    private double amount;
    private double percent;
    private long id; // persisted 
record id (if saved)

    public CalculateResponse
(String type, double amount, 
double percent, long id){
        this.type = type; 
this.amount = amount; this.percent = 
percent; this.id = id;
    }
    // getters
    public String getType(){return type;}
    public double getAmount(){return amount;}
    public double getPercent(){return percent;}
    public long getId(){return id;}
}

Service: CalculationService.java

package com.example.profitloss.service;

import com.example.profitloss.
dto.CalculateRequest;
import com.example.profitloss.
model.Calculation;
import com.example.profitloss.
repo.CalculationRepository;
import org.springframework.
stereotype.Service;

@Service
public class CalculationService {

    private final CalculationRepository repo;

    public CalculationService
(CalculationRepository repo){
        this.repo = repo;
    }

    public Calculation calculateAndSave
(double cp, double sp){
        if (cp == sp) {
            Calculation calc = new 
Calculation(cp, sp, 0.0, 0.0, false);
            return repo.save(calc);
        }
        boolean isProfit = sp > cp;
        double amount = Math.abs(sp - cp);
        double percent = (amount / cp) * 100;
        Calculation calc = new 
Calculation(cp, sp, amount, percent, isProfit);
        return repo.save(calc);
    }
}

Controller (REST): CalculationController.java

package com.example.profitloss.controller;

import com.example.profitloss.
dto.CalculateRequest;
import com.example.profitloss.
dto.CalculateResponse;
import com.example.profitloss.
model.Calculation;
import com.example.profitloss.
service.CalculationService;
import jakarta.validation.Valid;
import org.springframework.http.
ResponseEntity;
import org.springframework.web.
bind.annotation.*;

@RestController
@RequestMapping("/api")
public class CalculationController {

    private final CalculationService service;

    public CalculationController
(CalculationService service){
        this.service = service;
    }

    // POST /api/calculate -> saves 
to DB and returns result
    @PostMapping("/calculate")
    public ResponseEntity<CalculateResponse>
 calculateAndSave(@Valid @RequestBody
 CalculateRequest req) {
        Calculation saved = service.
calculateAndSave(req.getCp(), req.getSp());
        String type;
        if (saved.getAmount() == 0.0) 
type = "no-profit-no-loss";
        else type = saved.isProfit() ?
 "profit" : "loss";
        CalculateResponse resp = new
 CalculateResponse(type, saved.getAmount(), 
saved.getPercent(), saved.getId());
        return ResponseEntity.ok(resp);
    }

    // GET /api/calculation/{id} -> 
fetch saved calculation
    @GetMapping("/calculation/{id}")
    public ResponseEntity<Calculation>
 getById(@PathVariable Long id) {
        return service.repo.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.
notFound().build());
    }
}

Note: For brevity service.repo was used in controller GET. In production extract via service method.

Application main

package com.example.profitloss;

import org.springframework.boot.
SpringApplication;
import org.springframework.boot.
autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProfitlossServiceApplication {
    public static void main(String[] args){
        SpringApplication.run
(ProfitlossServiceApplication.class, args);
    }
}

How to run

  1. Start MySQL and create DB profitlossdb (or let JPA create; ensure user has privileges).
    Example:
    CREATE DATABASE profitlossdb;
    
  2. Update application.properties credentials.
  3. mvn spring-boot:run or build jar.

Example REST call (curl)

curl -X POST http://localhost:
8080/api/calculate \
 -H "Content-Type: application/json" \
 -d '{"cp":500,"sp":650}'

Response:

{"type":"profit","amount":
150.0,"percent":30.0,"id":1}

2) MySQL Integration (already included above)

  • JPA entity Calculation persists each calculation.
  • spring.jpa.hibernate.ddl-auto=update will create the table automatically.
  • You can query results via JPA repository or exposed REST endpoint.

If you want explicit SQL schema:

CREATE TABLE calculation (
  id BIGINT AUTO_INCREMENT PRIMARY KEY,
  cp DOUBLE,
  sp DOUBLE,
  amount DOUBLE,
  percent DOUBLE,
  is_profit BOOLEAN,
  created_at TIMESTAMP DEFAULT
 CURRENT_TIMESTAMP
);

3) REST API (standalone description)

The Spring Boot app provides:

  • POST /api/calculate — accepts JSON { "cp": <number>, "sp": <number> } and returns { type, amount, percent, id }. Saves to DB.
  • GET /api/calculation/{id} — fetch saved record.

Validation: @Min(0) on input; add more error handling as needed.

4) Kotlin Android App (Android Studio)

Minimum: Android Gradle Plugin + Kotlin. Create new project (Empty Activity) and replace files.

res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:padding="24dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/etCP"
        android:hint="Cost Price (CP)"
        android:inputType="numberDecimal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/etSP"
        android:hint="Selling Price (SP)"
        android:inputType="numberDecimal"
        android:layout_marginTop="12dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btnCalculate"
        android:text="Calculate"
        android:layout_marginTop="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tvResult"
        android:textSize="18sp"
        android:layout_marginTop="18dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

MainActivity.kt

package com.example.profitlossapp

import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private lateinit var etCP: EditText
    private lateinit var etSP: EditText
    private lateinit var btnCalculate: Button
    private lateinit var tvResult: TextView

    override fun onCreate(savedInstanceState:
 Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        etCP = findViewById(R.id.etCP)
        etSP = findViewById(R.id.etSP)
        btnCalculate = findViewById
(R.id.btnCalculate)
        tvResult = findViewById(R.id.tvResult)

        btnCalculate.setOnClickListener {
            val cpText = etCP.text.
toString().trim()
            val spText = etSP.text.
toString().trim()
            if (cpText.isEmpty() || 
spText.isEmpty()) {
                tvResult.text = 
"Please enter both CP and SP."
                return@setOnClickListener
            }

            val cp = cpText.toDoubleOrNull()
            val sp = spText.toDoubleOrNull()
            if (cp == null || sp == null) {
                tvResult.text = 
"Invalid numbers."
                return@setOnClickListener
            }
            if (cp == 0.0) {
                tvResult.text = 
"CP cannot be zero for percentage calculation."
                return@setOnClickListener
            }

            when {
                sp > cp -> {
                    val profit = sp - cp
                    val percent = 
profit / cp * 100
                    tvResult.text =
 "Profit: %.2f\nProfit %%: %.2f".
format(profit, percent)
                }
                cp > sp -> {
                    val loss = cp - sp
                    val percent = 
loss / cp * 100
                    tvResult.text = 
"Loss: %.2f\nLoss %%: %.2f".format
(loss, percent)
                }
                else -> {
                    tvResult.text = 
"No Profit, No Loss."
                }
            }
        }
    }
}

Optional: Call Spring Boot REST from Android

  • Add Retrofit or OkHttp to build.gradle and POST to /api/calculate to persist results remotely.

Final notes & next steps

  • The Spring Boot project already includes REST endpoints and MySQL JPA integration — that covers items (1)-(3).
  • The Kotlin Android project is a simple UI app; it can be extended to call the REST API to persist calculations remotely.

Mastering Java Code Format for Readability

  Mastering Java Code Format for Readability Writing code that works is only part of being a good programmer. Writing code that is easy to...