{"id":15131476,"url":"https://github.com/frankkwabenaaboagye/spring-mini-apps","last_synced_at":"2026-01-18T20:33:11.431Z","repository":{"id":255508647,"uuid":"852302037","full_name":"frankkwabenaaboagye/spring-mini-apps","owner":"frankkwabenaaboagye","description":"Spring Based Applications","archived":false,"fork":false,"pushed_at":"2024-12-13T15:38:30.000Z","size":61097,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-11T23:55:32.101Z","etag":null,"topics":["aop","rest","spring","spring-actuator","spring-boot","testing","transactions"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/frankkwabenaaboagye.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-04T15:19:15.000Z","updated_at":"2024-12-13T15:38:34.000Z","dependencies_parsed_at":"2024-10-31T12:37:51.949Z","dependency_job_id":null,"html_url":"https://github.com/frankkwabenaaboagye/spring-mini-apps","commit_stats":null,"previous_names":["frankkwabenaaboagye/spring-mini-apps"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frankkwabenaaboagye%2Fspring-mini-apps","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frankkwabenaaboagye%2Fspring-mini-apps/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frankkwabenaaboagye%2Fspring-mini-apps/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frankkwabenaaboagye%2Fspring-mini-apps/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/frankkwabenaaboagye","download_url":"https://codeload.github.com/frankkwabenaaboagye/spring-mini-apps/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247399886,"owners_count":20932880,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aop","rest","spring","spring-actuator","spring-boot","testing","transactions"],"created_at":"2024-09-26T03:42:13.417Z","updated_at":"2026-01-18T20:33:11.424Z","avatar_url":"https://github.com/frankkwabenaaboagye.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# General Info\n\nTo import into your IDE, import the parent pom `lab/pom.xml` as Maven projects or `lab/build.gradle` as Gradle projects.\n\n# Note\n\nSome Tips\n\n- credit: spring docs, spring academy, spring team\n\n# Content\n\n1. [Configuration](#configuration)\n2. [Component Scanning](#component-scanning)\n3. [Spring Container](#spring-container)\n4. [AOP](#aop)\n5. [JDBC](#jdbc)\n6. [Transaction](#transaction)\n7. [SpringBoot](#spring-boot)\n8. [SpringBoot Testing](#spring-boot-testing)\n9. [Securing REST Application with Spring Security](#securing-rest-application-with-spring-security)\n10. [Actuator](#actuator)\n\n## Configuration\n\nTODO\n\n## Component Scanning\n\nTODO\n\n## Spring Container\n\nTODO\n\n## AOP\n\n- There are some generic functionalities that are needed in many places in any application code\n- With this in mind, there is the need to avoid code tangling and eliminate code scattering\n- what can we do? Modularize🧩? Yes!\n- AOP helps to do that 💡\n- AOP Technologies - AspectJ, Spring AOP\n- Core concepts\n  - `Join Point`: A point in the execution of a program - Method calls or exception\n  - `Pointcut` : Expression that selects one or more `join point`\n  - `Advice` : Code to be executed at each selected `join point`\n  - `Aspect` : Module that encapsulated `Pointcuts` \u0026 `Advice`\n  - `Weaving` : Combining `Aspects` with main code\n- Defining a pointcut\n  - Spring AOP uses AspectJ expression language for selecting where to apply advice\n  - When defining pointcut, we're defining designators\n  - Designators - `execution`, e.t.c\n\n```java\n// format\nexecution( \u003cmethod pattern\u003e )\n\n// chain together with \u0026\u0026, ||, !\nexecution( \u003cpattern 1\u003e ) \u0026\u0026 execution( \u003cpattern 2\u003e )\n\n// method pattern\n[modifiers] ReturnType [ClassType] MethodName(Arguments) [throws ExceptionType]\n    // two mandatory things:\n        // ReturnType and\n        // MethodName with Arguments\n\n```\n\n- Advice Types\n  - `Before` ⏩\n    - Proxy delegates to the advice before delegating to the target⚙️\n    - do whatever you want in the advice before executing the business logic\n    - if you happen to put an exception on the advice, you prevent the target from executing\n      - good for security🔒 use cases\n  - `AfterReturning` ↩️\n    - Proxy first delegates to the target⚙️\n    - then the proxy delegates to the advice\n      - This only happens when there is a successful return from the target\n      - there will be more information here because, you will have\n        - the context information\n        - with the return from the target\n  - `AfterThrowing` ⚠️\n    - Proxy first delegate to the target⚙️\n    - then the proxy delegates to the advice\n      - This only happens when there is an exception thrown from the target\n      - you will have the exception available to you\n      - you can throw another exception or allow it to propagate\n        - there is a work around this\n  - `After` 🔚\n    - Proxy delegate to the target⚙️\n    - then proxy delegate to the advice\n    - whether there is a success reutrn or exception, it does not matter\n    - advice is excuted after the target⚙️\n  - `Around` 🔄\n    - Proxy delegates to the advice\n    - it is your responsibility to call `proceed` method to the target⚙️\n    - in this way, you can excute things before and after the target - cool! 😎\n- Limitations of spring aop\n  - can only advise non-private methods\n  - can only advise spring beans\n  - inner method call inside of a target would not get advised\n- Note: AspectJ does not have this limitations\n\n## JDBC\n\n- There are issues with plain Jdbc\n  - boilerplate code\n  - forced to catch certain exceptions\n  - forced to close resources\n- Spring JDBC Template solves these issues\n  - with a simple statement, spring will be able to handle for us\n    - connection\n    - statement execution\n    - result set processsing\n    - exceptions\n    - release of connection\n- Note: When creating the Jdbc, we need a `datasource`\n- Basic Usage\n  - For simple Types\n  - For Generic Maps\n  - For Domain Objects\n\n```java\n// for simple types\n\njdbcTemplate.queryForObject(the_sql, the_return_class);\n\nString sql = \"select count(*) from PERSON\";\njdbcTemplate.queryForObject(sql, Long.class);\n\n    // you can bind variables too\n    String sql = \"insert into PERSON(first_name, last_name) values(?, ?)\";\n    jdbcTemplate.update(sql, \"Kay\", \"Lee\");\n        /* Note: Use the `update` method\n             to perfom - insert, update, delete\n        */\n\n// for generic maps\n    // can return each row of a ResultSet as a map\njdbcTemplate.queryForList(...);\njdbcTemplate.queryForMap(...);   // watch out for memory consumption\n\n    // example\n    String sql = \"select * from PERSON where id=?\";\n    int id = 1;\n    jdbcTemplate.queryForMap(sql, id);  // this returns: Map\u003cString, Object\u003e\n\n    String sql = \"select * from PERSON\";\n    jdbcTemplate.queryForList(sql); // returns: List\u003cMap\u003cString, Object\u003e\u003e\n\n\n// Domain Object queries\n    // you have to use call back approach\n        - RowMapper\n        - ResultSetExtractor\n        - RowCallbackHandler\n\n\njdbcTemplate\n.queryForObject(\n    String sql,\n    RowMapper\u003cT\u003e rowMapper,\n    Object... args\n)\n.queryForObject(\n    String sql,\n    RowMapper\u003cT\u003e rowMapper\n)\n\n\n    // examples\n        // single row\n            String sql = \"select first_name, last_name from PERSON where id=?\";\n\n                // here we define row mapper using lambda\n            jdbc.queryForObject(\n                sql,\n                (rs, rowNum)-\u003e new Person(rs.getString(\"first_name\"), rs.getString(\"last_name\")),\n                id\n            );\n                // the above returns `Person` domain object\n\n        // multiple rows\n            String sql = \"select first_name, last_name from PERSON\";\n\n                // here we define row mapper using lambda also\n            jdbc.queryForObject(\n                sql,\n                (rs, rowNum)-\u003e new Person(rs.getString(\"first_name\"), rs.getString(\"last_name\"))\n            );\n                // the above returns `List\u003cPerson\u003e` domain object\n\n\n\n```\n\n```java\n// Examples\n\n// before - plain jdbc\npublic Restaurant findByMerchantNumber(String merchantNumber) {\n    String sql = \"select MERCHANT_NUMBER, NAME, BENEFIT_PERCENTAGE, BENEFIT_AVAILABILITY_POLICY\"\n            + \" from T_RESTAURANT where MERCHANT_NUMBER = ?\";\n    Restaurant restaurant = null;\n\n    try (Connection conn = dataSource.getConnection();\n            PreparedStatement ps = conn.prepareStatement(sql) ){\n        ps.setString(1, merchantNumber);\n        ResultSet rs = ps.executeQuery();\n        advanceToNextRow(rs);\n        restaurant = mapRestaurant(rs);\n    } catch (SQLException e) {\n        throw new RuntimeException(\"SQL exception occurred finding by merchant number\", e);\n    }\n\n    return restaurant;\n}\n\n// after - refactored\n\n\tpublic Restaurant findByMerchantNumber(String merchantNumber) {\n\t\tString sql = \"select MERCHANT_NUMBER, NAME, BENEFIT_PERCENTAGE, BENEFIT_AVAILABILITY_POLICY\"\n\t\t\t\t+ \" from T_RESTAURANT where MERCHANT_NUMBER = ?\";\n\n\t\tRestaurant restaurant = jdbcTemplate.queryForObject(\n            sql,\n            (rs, rowNum) -\u003e mapRestaurant(rs),\n            merchantNumber\n        );\n\n\t\treturn restaurant;\n\t}\n\n//--------------------------------\n\n// before\npublic void updateBeneficiaries(Account account) {\n    String sql = \"update T_ACCOUNT_BENEFICIARY SET SAVINGS = ? where ACCOUNT_ID = ? and NAME = ?\";\n    Connection conn = null;\n    PreparedStatement ps = null;\n    try {\n        conn = dataSource.getConnection();\n        ps = conn.prepareStatement(sql);\n        for (Beneficiary beneficiary : account.getBeneficiaries()) {\n            ps.setBigDecimal(1, beneficiary.getSavings().asBigDecimal());\n            ps.setLong(2, account.getEntityId());\n            ps.setString(3, beneficiary.getName());\n            ps.executeUpdate();\n        }\n    } catch (SQLException e) {\n        throw new RuntimeException(\"SQL exception occurred updating beneficiary savings\", e);\n    } finally {\n        if (ps != null) {\n            try {\n                // Close to prevent database cursor exhaustion\n                ps.close();\n            } catch (SQLException ex) {\n            }\n        }\n        if (conn != null) {\n            try {\n                // Close to prevent database connection exhaustion\n                conn.close();\n            } catch (SQLException ex) {\n            }\n        }\n    }\n}\n\n// after\n\npublic void updateBeneficiaries(Account account) {\n    String sql = \"update T_ACCOUNT_BENEFICIARY SET SAVINGS = ? where ACCOUNT_ID = ? and NAME = ?\";\n\n\n    for (Beneficiary beneficiary : account.getBeneficiaries()) {\n        jdbcTemplate.update(sql, beneficiary.getSavings().asBigDecimal(), account.getEntityId(), beneficiary.getName());\n    }\n\n}\n\n\n\n```\n\n```java\n\n// utilise lambda\n\n    // consider\n    jdbcTemplate.queryForObject(sql, new RowMapper\u003cRestaurant\u003e() {\n        @Override\n        public Restaurant mapRow(ResultSet rs, int rowNum) throws SQLException {\n            return mapRestaurant(rs);\n        }\n    });\n\n    // same as\n\n    jdbcTemplate.queryForObject(sql, (rs, rowNum) -\u003e mapRestaurant(rs)); // much better\n\n\n// another example\n\n    // consider\n    jdbcTemplate.query(\n        sql,\n        new ResultSetExtractor\u003cAccount\u003e() {\n\t\t\t@Override\n\t\t\tpublic Account extractData(ResultSet rs) throws SQLException, DataAccessException {\n\t\t\t\treturn mapAccount(rs);\n\t\t\t}\n\t\t},\n        creditCardNumber\n    );\n\n    // same as\n    jdbcTemplate.query(\n        sql,\n        rs -\u003e {\n            return mapAccount(rs);\n        },\n        creditCardNumber\n    );\n\n    // same as\n    jdbcTemplate.query(\n        sql,\n        this::mapAccount,\n        creditCardNumber\n    );\n\n\n// by the way; the mapAcount method is shown below\n    /*\n\tprivate Account mapAccount(ResultSet rs) throws SQLException {\n\t\tAccount account = null;\n\t\twhile (rs.next()) {\n\t\t\tif (account == null) {\n\t\t\t\tString number = rs.getString(\"ACCOUNT_NUMBER\");\n\t\t\t\tString name = rs.getString(\"ACCOUNT_NAME\");\n\t\t\t\taccount = new Account(number, name);\n\t\t\t\t// set internal entity identifier (primary key)\n\t\t\t\taccount.setEntityId(rs.getLong(\"ID\"));\n\t\t\t}\n\t\t\taccount.restoreBeneficiary(mapBeneficiary(rs));\n\t\t}\n\t\tif (account == null) {\n\t\t\t// no rows returned - throw an empty result exception\n\t\t\tthrow new EmptyResultDataAccessException(1);\n\t\t}\n\t\treturn account;\n\t}\n    */\n\n```\n\n## Transaction\n\n- We have to adhere to the ACID\n  {Atomicity, Consistency, Isolation, Durable}\n  principles when it comes to the data access layer right?\n- When running non transactionally, there could be issues like:\n  - separate connections for separate method calls\n  - partial failures might be a problem too\n- we need deal with this\n  - with transactions\n    - we become very efficient, because same connection is used for each operation\n    - also operations complete as an atomic unit\n- Spring Transaction Management\n  1. Declare a `PlatformTransactionManager` bean\n     - note that there are several implementations availbel\n       - DataSourceTM, JmsTM, JpaTM , e.t.c.\n  2. Declare the transactional methods\n     - you can use annotations(recommended), or go the programmatic way, or even do both\n  3. Add the `@EnableTransactionManagement` to a configuration class\n\n```java\n\n// examples\n\n\t@Bean\n\tpublic DataSource dataSource(){\n        ...\n        ...\n\t}\n\n\t@Bean\n\tpublic PlatformTransactionManager transactionManager(){\n\t\treturn new DataSourceTransactionManager(dataSource());\n\t}\n\n    //----\n\n    @Configuration\n    @EnableTransactionManagement\n    public class RewardsConfig {\n        ...\n        ...\n    }\n\n```\n\n## Spring Boot\n\nIn a Spring application, we typically need to:\n\n- Configure dependencies in the pom.xml file\n- Set up configurations in the application context\n\nHowever, many of these components can be predicted, so why not let Spring Boot handle them for us?\n\n- Spring Boot automates low-level configurations\n\n  - This requires it to make certain decisions (hence, it has its own opinions)\n    - Essentially, Spring Boot takes an opinionated approach to the Spring framework and third-party libraries\n    - However, we still have the ability to override these defaults.\n  - Important note:\n    - Spring Boot is not a code generator; all configurations happen at runtime.\n\n- Spring Boot features\n  - dependency Management\n    - `pom` file and starter dependencies\n  - auto configuration\n    - `@SpringBootApplication`\n      - represents the combination of - `@EnableAutoConfiguration`,\n        `@ComponentScan`, and `@SpringBootConfiguration`\n  - packaging and runtime\n  - integration testing\n- Getting started\n  - 3 files needed\n    - to set up spring boot and other dependencies - `pom.xml`\n    - for general configuration - `application.properties`\n    - the application launcher - `application.class` (entry point)\n  - use : start.spring.io\n  - or : spring-io/initializr on github\n\n- Spring Data Jpa\n  - The `Spring Data` provides a consistent programming model across different data stores\n  - It create Instant Repository\n\n- Web application\n  - Spring MVC\n    - lifecycle of a request\n      - *Request Lifecycle in Spring MVC*\n        - The **`Dispatcher Servlet`** is the core of Spring MVC and handles all incoming requests.\n        - However, it doesn't process them directly.\n        - It delegates the request to **`Handler Mapping`**, which identifies the appropriate controller for the request.\n        - Once the controller is identified, the Dispatcher Servlet passes the request to the **`Handler Adapter`**.\n            - The handler adapter adapts the request, passing necessary parameters (e.g., request data, URI variables) to the controller.\n            - The **`Controller`** returns a response:\n                - For server-side rendering, it returns a **`Model and View`**, where the view is a logical view.\n                - The view is resolved by the **`View Resolver`**, which locates and creates the actual view instance.\n            - Based on the model returned by the controller, the Dispatcher Servlet renders the view to the user.\n        - If the controller returns an object (like JSON or XML), the Dispatcher Servlet delegates it to **`Message Converters`**.\n            - The response from the message converters is then sent to the user.\n\n\n## Spring Boot Testing\n  - `@SpringBootTest` registers a TestRestTemplate bean.\n  - `TestRestTemplate` is, by design, fault tolerant. \n    - This means that it does not throw exceptions when an error response (400 or greater) is received.\n  - To test Spring MVC Controllers, you can use `@WebMvcTest`. \n    - It auto-configures the Spring MVC infrastructure (and nothing else) for the web slice tests.\n  - Note that the Web slice testing runs faster than an integration testing since it does not need to start a server.\n\n```java\n\nBDDMockito: given(..), willReturn(..), willThrow(..)\nMockMvc: perform(..)\nResultActions: andExpect(..)\nMockMvcRequestBuilders: get(..), post(..), put(..), delete(..)\nMockMvcResultMatchers: status(), content(), jsonPath(..), header()\n\n```\n\n  - Note that `@WebMvcTest` auto-configures MockMvc bean.\n\n```java\n\n// example\n\t@Test\n\tpublic void accountDetails() throws Exception {\n\n\t\tgiven(accountManager.getAccount(0L))\n\t\t\t\t.willReturn(new Account(\"1234567890\", \"John Doe\"));\n\n\t\tmockMvc.perform(get(\"/accounts/0\"))\n\t\t\t   .andExpect(status().isOk())\n\t\t\t   .andExpect(content().contentType(MediaType.APPLICATION_JSON))\n\t\t\t   .andExpect(jsonPath(\"name\").value(\"John Doe\"))\n\t\t\t   .andExpect(jsonPath(\"number\").value(\"1234567890\"));\n\n\t\tverify(accountManager).getAccount(0L);\n\n\t}\n\n```\n\n## Securing REST Application with Spring Security\n\n## Actuator","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrankkwabenaaboagye%2Fspring-mini-apps","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrankkwabenaaboagye%2Fspring-mini-apps","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrankkwabenaaboagye%2Fspring-mini-apps/lists"}