Spring boot restful API

Restful API expresses CRUD operations through HTTP, the following is a set of Restful APIs to add, delete, modify and list FX currency values.

URLHTTP Methodfunction
/fxPOSTlist all the FX values
/fx/{id}GETget FX values
/fx/{id}DELETEdelete FX
/fx/{id}PUTupdate FX

The URL is only the way to identify the resource, and the specific behavior is specified by the HTTP method

Now let’s take a look at how to implement the above interface

 @RestController
 @RequestMapping("/rest")
 public class FxRestController {
  
     @Autowired
     private FxService fxService;
  
     @RequestMapping(value = "/fx", method = POST, produces = "application/json")
     public WebResponse<Map<String, Object>> saveFx(@RequestBody Fx fx) {
         fx.setUserId(1L);
         fxService.saveFx(fx);
         Map<String, Object> ret = new HashMap<>();
         ret.put("id", fx.getId());
         WebResponse<Map<String, Object>> response = WebResponse.getSuccessResponse(ret);
         return response;
     }
  
     @RequestMapping(value = "/fx/{id}", method = DELETE, produces = "application/json")
     public WebResponse<?> deleteFx(@PathVariable Long id) {
         Fx fx = fxService.getById(id);
         fx.setStatus(-1);
         fxService.updateFx(fx);
         WebResponse<Object> response = WebResponse.getSuccessResponse(null);
         return response;
     }
  
     @RequestMapping(value = "/fx/{id}", method = PUT, produces = "application/json")
     public WebResponse<Object> updateFx(@PathVariable Long id, @RequestBody Fx fx) {
         fx.setId(id);
         fxService.updateFx(fx);
         WebResponse<Object> response = WebResponse.getSuccessResponse(null);
         return response;
     }
  
     @RequestMapping(value = "/fx/{id}", method = GET, produces = "application/json")
     public WebResponse<Article> getFx(@PathVariable Long id) {
         Fx fx = fxService.getById(id);
         WebResponse<Fx> response = WebResponse.getSuccessResponse(fx);
         return response;
     }
 } 

Let’s analyze this code again.

  1. We use the @RestController instead of @Controller, but this is also not provided by Spring boot, but provided in Spring MVC4
  2. There are three URL mappings in this class that are the same, they are all /fx/{id}, which is not allowed in the class @Controller.
  3. The @PathVariable is also provided by Spring MVC

So it seems that this code still has nothing to do with Spring boot. Spring boot only provides automatic configuration functions.

Let’s send some http requests with postman to see the results.

Posted in Development | Tagged , , | Leave a comment

Finding the nearby people/vehicle through latitude and longitude

Now that we know the latitude and longitude of the user’s current location and the range we are going to search, i.e. a center point and radius, the maximum and minimum values of longitude and latitude.

First declare a function to calculate the range of latitude and longitude

 /**
  * Calculate the range based on the latitude, longitude and radius
  * @param string $latitude
  * @param String $longitude
  * @param float $radius 
  * @return Array 
  */
 private function calcScope($latitude, $longitude, $radius) {
   $degree = (24901 * 1609) / 360.0;
   $dpmLatitude = 1 / $degree;
   $radiusLatitude = $dpmLatitude * $radius;
   $minLatitude = $latitude - $radiusLatitude;    // min latitude
   $maxLatitude = $latitude + $radiusLatitude;    // max latitude
   
   $mpdLongitude = $degree * cos($latitude * (PI / 180));
   $dpmLongitude = 1 / $mpdLongitude;
   $radiusLongitude = $dpmLongitude * $radius;
   $minLongitude = $longitude - $radiusLongitude;   // min longitude
   $maxLongitude = $longitude + $radiusLongitude;   // max longitude
   
   $scope = array(
     'minLatitude'  => $minLatitude,
     'maxLatitude'  => $maxLatitude,
     'minLongitude'  => $minLongitude,
     'maxLongitude'  => $maxLongitude
     );
   return $scope;
 } 

The returned array contains the maximum and minimum latitude and longitude that meet the conditions

Then we can find all the records that meet the conditions from the database

 /**
  * search those latitude, longitude are within range
  * @param String $latitude  
  * @param String $longitude  
  * @param float $radius 
  * @return Array     
  */
 public function searchByLatAndLng($latitude, $longitude, $radius) {
   $scope = $this->calcScope($latitude, $longitude, $radius);   // get the min and max for latitude and logitude
 

   $sql = 'SELECT id, type, latitude, longitude FROM last_location WHERE `latitude` < '.$scope['maxLatitude'].' and `latitude` > '.$scope['minLatitude'].' and `longitude` < '.$scope['maxLongitude'].' and `longitude` > '.$scope['minLongitude'];
   $sth = $dbh->query($sql);
   $result = $sth->fetchAll(PDO::FETCH_ASSOC); 
   return $result;
 } 

Now we have the result that are within the range, we could calculate the actual distance.

/**
  * calculate the distance (KM)
  * @param string $lat1 latitude 1
  * @param String $lng1 longitude 1
  * @param String $lat2 latitude 2
  * @param String $lng2 longitude 2
  * @return float  return the distance in km
  */
 public function calcDistance($lat1, $lng1, $lat2, $lng2) {
 

   $lat1 = doubleval($lat1);
   $lng1 = doubleval($lng1);
   $lat2 = doubleval($lat2);
   $lng2 = doubleval($lng2);
   
   /** calculation by google */
   $theta = $lng1 - $lng2;
   $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
   $dist = acos($dist);
   $dist = rad2deg($dist);
   $miles = $dist * 60 * 1.1515;
   return ($miles * 1.609344);
 } 
Posted in Development | Tagged | Leave a comment

Laravel using google captcha validation

install captcha dependence with composer

composer require buzz/laravel-google-captcha

add the class interface into ‘providers’ section in config/app.php

Buzz\LaravelGoogleCaptcha\CaptchaServiceProvider::class,

define alias into the ‘alias’ section

'GoogleCaptcha' => Buzz\LaravelGoogleCaptcha\CaptchaServiceProvider::class,

execute command to create configuration file

php artisan vendor:publish

edit the config file accordingly in config/captcha.php

/*
  * Secret key and Site key get on https://www.google.com/recaptcha
  * */
 return [
     'secret' => env('CAPTCHA_SECRET', 'default_secret'),
     'sitekey' => env('CAPTCHA_SITEKEY', 'default_sitekey'),
     /**
      * @var string|null Default ``null``.
      * Custom with function name (example customRequestCaptcha) or class@method (example \App\CustomRequestCaptcha@custom).
      * Function must be return instance, read more in repo ``https://github.com/thinhbuzz/laravel-google-captcha-examples``
      */
     'request_method' => null,
     'options' => [
         'multiple' => false,
         'lang' => app()->getLocale(),
     ],
     'attributes' => [
         'theme' => 'light'
     ],
 ]; 

the code to show the captcha in the form

{!! Captcha::display($attributes) !!}
Posted in Development | Tagged , , | Leave a comment

Laravel Restful API

Its not difficult to create restful API with Laravel.

First create controller for handling data

php artisan make:controller api/FxInfoController --api

This will create the controller with some dummy functions index() show() store() update() destory()

Update the api/FxInfoController.php

<?php
 
 namespace App\Http\Controllers\api;

 use App\Http\Controllers\Controller;
 use Illuminate\Http\Request;
 use App\FxInfo;
 
 class FxInfoController extends Controller
 {
     /**
      * Display a listing of the resource.
      *
      * @return \Illuminate\Http\Response
      */
     public function index()
     {
         return response()->json(FxInfo::all(), 200);
     }

     /**
      * Store a newly created resource in storage.
      *
      * @param  \Illuminate\Http\Request  $request
      * @return \Illuminate\Http\Response
      */
     public function store(Request $request)
     {
         $fxInfo = UserInfo::create($request->all());
 

         return response()->json($fxInfo, 201);
     }

     /**
      * Display the specified resource.
      *
      * @param  int  $id
      * @return \Illuminate\Http\Response
      */
     public function show(FxInfo $fxInfo)
     {
         return response()->json($fxInfo, 200);
     }
 

     /**
      * Update the specified resource in storage.
      *
      * @param  \Illuminate\Http\Request  $request
      * @param  int  $id
      * @return \Illuminate\Http\Response
      */
     public function update(Request $request, FxInfo $fxInfo)
     {
         $fxInfo->update($request->all());

         return response()->json($fxInfo, 200);
     }
 
     /**
      * Remove the specified resource from storage.
      *
      * @param  int  $id
      * @return \Illuminate\Http\Response
      */
     public function destroy(FxInfo $fxInfo)
     {
         $fxInfo->delete();
 

         return response()->json(null, 204);
     }
 } 

Now update the routes/api.php to define where to go
e.g. http://127.0.0.1:8000/api/fx will go to api\FxInfoController.php index() function

Route::get(‘fx’, ‘api\FxInfoController@index’);
Route::get(‘fx/{fxInfo}’, ‘api\FxInfoController@show’);
Route::post(‘fx’, ‘api\FxInfoController@store’);
Route::put(‘fx/{fxInfo}’, ‘api\FxInfoController@update’);
Route::delete(‘fx/{fxInfo}’, ‘api\FxInfoController@destroy’);

A simple Restful API is done, we can try it with Postman

Posted in Development | Tagged , , | Leave a comment

Laravel Datatable with json data

Prepare the view with table and javascript

var fx_currency = $('#fx_currency_table').DataTable({
       processing: true,
       serverSide: true,
       bPaginate: true,
       buttons:[],
       ajax: '/fxcurrency',
       columnDefs: [ {
         "targets": 4,
         "orderable": false,
         "searchable": false
         } ]
 });
<div class="card-body">
  <table class="table table-border table-striped" id="fx_currency_table" width="100%>
    <thread>
      <tr>
        <th>Currency Code</th>
        <th>DSP</th>
        <th>Bid</th>
        <th>Ask</th>
        <th>@lang('message.action')</th>
      </tr>
    </thread>
  </table>
</div>

Laravel Controller

 public function index()
     {
         if (!auth()->user()->can('user.view') && !auth()->user()->can('user.create')) {
             abort(403, 'Unauthorized action.');
         }         

         if (request()->ajax()) {
           $business_id = request()->session()->get('user.business_id');
           $fxcurrency = FxCurrency::where('business_id', $business_id)
                       ->select(['currency_code', 'id', 'dsp', 'ask', 'bid']);
 
             return Datatables::of($fxcurrency)
                 ->addColumn(
                     'action',
                     '
                     <button data-href="{{action(\'FxCurrencyController@edit\', [$id])}}" class="btn btn-xs btn-info btn-modal" data-container=".fxcurrency_edit_modal"><i class="fas fa-edit"></i> Edit</button>
                     &nbsp;
    <button data-href="{{action(\'FxCurrencyController@destroy\', [$id])}}" class="btn btn-xs btn-modal btn-info delete_user_button" data-container=".location_edit_modal"><i class="fas fa-trash-alt"></i> Delete</button>
                    ‘
                 )
                 ->removeColumn('id')
                 ->rawColumns([4])
                 ->editColumn('ask', function($fxcurrency) {
                   return $this->util->pack_dsp($fxcurrency->ask, $fxcurrency->dsp);
                 })
                 ->editColumn('bid', function($fxcurrency) {
                   return $this->util->pack_dsp($fxcurrency->bid, $fxcurrency->dsp);
                 })
                 ->make(false)
                 ;
         }
         return view('fx_currency.index');
     } 
Posted in Development | Tagged , , , | Leave a comment