IntelliJ IDEA下Maven SpringMVC+Mybatis入門搭建例子


 

很久之前寫了一篇SSH搭建例子,由於工作原因已經轉到SpringMVC+Mybatis,就以之前SSH實現簡單登陸的例子,總結看看SpringMVC+Mybatis怎么實現。

Spring一開始是輕量級的框架,在SSH中,處於中間粘合劑的作用,核心作用是IoC(控制反轉)、DI(依賴注入),IoC和DI是同一個概念,只是以不同角度進行解釋。簡單的說,就是Spring幫助你管理Bean,只要寫好了配置文件或者Spring注解,那么Spring可以自動幫你創建Bean,不需要手動new。經過后來的發展出現的SpringMVC框架,與Struts一樣,同屬於MVC框架的一種,SpringMVC可以說和Spring是兩回事了,已經是一個比較重的框架了,我的理解是SpringMVC=Struts+Spring了。

Spring還有另外一個重要組成部分是AOP(Aspect-Oriented Programming 面向切面編程),目前主要使用在攔截器方面。實際上Struts也有攔截器,概念是類似的。

Hibernate、Mybatis、ibatis都是常用的持久層框架,它們都遵從ORM設計,可以簡單的認為Hibernate比較重,Mybatis、ibatis比較輕量,Mybatis又是由ibatis發展來的,所以Mybatis與ibatis非常相似,阿里用的就是ibatis(畢竟當時還沒有Mybatis),三者之間的區別網上可以搜一下,就不展開說了。

IDE集成開發工具我也從MyEclipse轉到IntelliJ IDEA了(版本是2017.1.3),工具上使用肯定有一些區別,但是寫代碼上是沒有區別的。

一、建立Maven SpringMVC項目

首先還是要下載安裝好JDK,目前JDK版本已經到9,也不用特意去下載J2EE的版本,就下載一個J2SE版本的就可以,我下載的是JDK8的,開發環境是Windows,所以下載了一個Windows x64的jdk-8u161-windows-x64.exe(下載地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html),安裝好之后配置好環境變量,主要要設置JAVA_HOME和PATH兩個環境變量,CMD命令行敲java -version有版本信息展示就可以了。

另外為了更好的管理jar,我使用了maven(下載地址 https://maven.apache.org/download.cgi),網上搜索一下如何配置即可,主要配置MAVEN_HOME和PATH環境變量,在IDEA里還要在setting->Build,Execution,Deployment->Build Tools->Maven里設置Maven home directory、User setting file、Local repository。

使用IDEA創建maven SpringMVC項目的詳細過程請參考博文https://www.cnblogs.com/Sinte-Beuve/p/5730553.html,下面簡述步驟:

打開IDEA之后,File->new->Project,選擇如下maven-archetype-webapp

next,輸入GroupId和ArtifactId,next,next,輸入Project name

點擊finish,就創建好項目了,這時maven會首先去下載maven骨架,也就是項目組織結構配置文件,還有一些必要的jar包。

等maven下載完成之后,就得到了基本項目框架,參照上面博文,建立java目錄並標記source,建立相關pakage,項目框架就基本完成了,我的項目結構如下圖所示:

這時候,我們要利用maven加入springmvc、mybatis相關jar包,打開pom.xml,仿照如下添加properties和dependencies

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>springmvctest</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>springmvctest Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- spring版本號 -->
    <spring.version>4.1.6.RELEASE</spring.version>
    <!-- mybatis版本號 -->
    <mybatis.version>3.2.6</mybatis.version>
    <!-- log4j日志文件管理包版本 -->
    <slf4j.version>1.7.7</slf4j.version>
    <log4j.version>1.2.17</log4j.version>
    <!-- jackson包版本 -->
    <jackson.version>2.5.0</jackson.version>

  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <!--spring單元測試依賴 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${spring.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- springMVC核心包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <!-- spring核心包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.0.9.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <!-- AOP begin -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.7.4</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.7.4</version>
    </dependency>
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.1</version>
    </dependency>
    <!-- AOP end -->

    <!-- mybatis核心包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>${mybatis.version}</version>
    </dependency>

    <!--mybatis spring 插件 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.2.2</version>
    </dependency>

    <!-- Mysql數據庫驅動包 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.34</version>
    </dependency>

    <!--servlet-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

  </dependencies>
  <build>
    <finalName>springmvctest</finalName>
  </build>
</project>

如果后面還有需要下載的jar包,比如log4j等,可以去這個網站http://mvnrepository.com搜索相關jar包和版本,找到相關信息,也同樣寫一個dependency,maven就自動去下載了。

二、使用Spring

WEB-INF下的web.xml可以理解為整個項目的入口,無論是Struts還是Spring都是先從這個web.xml找到相關配置,再進入struts或是spring的框架中的。打開web.xml,修改為如下內容:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

以上就添加了Spring框架能力,DispatcherServlet顧名思義,就是轉發的意思,mapping的url-pattern寫的是/,說明所有請求都使用這個DispatcherServlet進行轉發。大家可以對比一下struts的配置文件,struts是使用filter的,而spring使用的是servlet。有了Dispatcher轉發,就需要再添加一個寫怎么樣轉發的配置文件dispatcher-servlet.xml,同樣在WEB-INF底下添加這個文件即可,dispatcher-servlet.xml文件內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <description>Spring Configuration</description>
    <!-- 靜態資源(js、image等)的訪問 -->
    <mvc:default-servlet-handler/>
    <!-- 配置注解驅動 可以將request參數與綁定到controller參數上 -->
    <mvc:annotation-driven />
    <!-- 開啟組件自動掃描;使用Annotation自動注冊Bean,解決事物失效問題:在主容器中不掃描@Controller注解,在SpringMvc中只掃描@Controller注解。  -->
    <!-- base-package 如果多個,用“,”分隔 -->
    <context:component-scan base-package="com.test.dao,com.test.service,com.test.controller" />
    <!-- 對模型視圖名稱的解析,即在模型視圖名稱添加前后綴(如果最后一個還是表示文件夾,則最后的斜杠不要漏了) 使用JSP-->
    <!-- 默認的視圖解析器 在上邊的解析錯誤時使用 (默認使用html)- -->
    <bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/view/"/><!--設置JSP文件的目錄位置-->
        <property name="suffix" value=".jsp"/>
    </bean>
 </beans>

<mvc:annotation-driven />這一句說明啟用自動掃描Spring注解,<context:component-scan base-package="com.test.dao,com.test.service,com.test.controller" />這句說明掃描的位置。defaultViewResolver這個bean主要是用來方便controller返回尋找jsp視圖,定義了jsp目錄位置是/WEB-INF/view/下面。

那么,這個時候,我們來先寫一個controller,名字就叫IndexController吧,用來處理Index主頁,其實就是登陸頁面。

package com.test.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Created by jeff on 2018/2/13.
 */
@Controller
@RequestMapping("/")
public class IndexController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String loginview(){
        return "loginview";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(@ModelAttribute("username") String username, @ModelAttribute("password") String password){
        if(username.equals("jeff") && password.equals("123"))
            return "index";
        return "loginview";
    }
}

可以看到,Class IndexController上面有兩個注解,一個是@Controller,說明這個Class是一個Controller,另一個是@RequestMapping,相當於訪問路徑。

在IndexController定義了兩個方法,loginview和login,方法上面同樣有@RequestMapping注解,細分訪問路徑,還定義了它是GET還是POST方法。

在login方法的參數username和password前面還有@ModelAttribute注解,這是對應頁面元素的name的,用於獲取頁面元素的值。這里其實就是依賴注入了,我們沒有初始化username和passowrd,就直接使用了,其實就是Spring幫我們獲取並初始化設置了頁面對應的值進username和password里了。

那么,return "loginview"和return "index"又是什么意思呢?這兩個方法的返回值都是String類型,返回給誰呢?剛剛上面dispatcher-servlet.xml文件中,咱們定義了defaultViewResolver這個bean,就是用來處理這個String的,返回一個index,那么Spring就會去你定義好的/WEB-INF/view/下面,找對應的jsp文件。所以,應該可以猜到,我們需要在/WEB-INF/view/下面新建兩個jsp文件,一個叫loginview.jsp,一個叫index.jsp。

loginview.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="zh-CN">
<body>
    <form method="get" action="/login">
        登錄名:<input name='username' type="text" /><br/>
        密碼:<input name ='password' type="password" /><br/>
        <button type="submit" style="width: 70px; height: 20px;">確定</button>
    </form>
</body>
</html>

index.jsp

<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

完成了這些,還不能運行起來,我們還有一個重要的東西還沒有,那就是tomcat或者jboss這些容器。初學者學習了幾個月,說不定其實還沒有了解什么是容器,容器是用來做什么的。首先,容器是指servlet容器,就是存放我們寫的servlet的。至於什么作用,其實大家從C寫面向過程過來的話,可以想一想,C里面必須有一個main函數,不然程序從哪里開始呢?學C++使用MFC框架時,我就發現沒有了main函數,覺得很奇怪,程序怎么知道從哪里進去呢?我們上面寫的代碼,配置文件,也沒有指定任何的main函數。其實main函數就是容器里的,可以想象成這個main函數一直在循環等待觸發事件,一旦收到點擊打開某個網頁之類的指令,那么容器就會去找相應的servlet進行處理。

也許您還會問:那什么又是servlet呢?簡單的說,就是實現了servlet接口的類或是繼承HttpServlet、GernericServlet的類都叫做servlet(通常繼承HttpServlet),可以覆寫doPost()、doGet()等方法。但是我們會發現,我們上面沒有一個類實現了servlet接口或繼承自HttpServlet、GernericServlet,那么http如何找到我們的Controller的呢?如上面提到的DispatcherServlet,它實現了servlet接口。這下大家應該明白,容器接收到http請求,找到web.xml看到配置了的DispatcherServlet,進入DispatcherServlet,由它轉到我們的Controller,進行后面的處理,Controller將處理結果返回給DispatcherServlet,然后通過doPost()或者doGet()返回頁面。

了解了這些,就去下載一個tomcat或者jboss容器,在idea里配置好就行了,我這里使用常用的tomcat,網上搜一下idea配置tomcat就可以了。

run之后,打開瀏覽器,輸入http://localhost:8080/就可以看到登陸頁面了

輸入jeff登錄名和123密碼,即可跳轉到index首頁,其他登陸名密碼則不會跳轉

三、使用Mybits

既然Mybatis是一個持久層框架,使用Mybatis之前,我們需要有一個數據庫,那么下載一個常用的開源免費的MySQL安裝配置好即可(https://dev.mysql.com/downloads/mysql/)。

安裝好之后,使用MySQLWorkbench連進去,進行創建數據庫、建表等操作。

create database springtest;
use springtest;

create table users
(
id int PRIMARY KEY AUTO_INCREMENT,
username varchar(20),
password varchar(50)
) auto_increment = 1;

insert into users(username,password) values('jeff','123');

相應的,我們可以在entity包下新建一個Users類,這個類就是常說的Model層的javaBean(但沒有實現序列化接口Serializable)

package com.test.entity;

import org.springframework.stereotype.Repository;

/**
 * Created by jeff on 2018/2/22.
 */
public class Users { private Integer id; private String username; private String password; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password;} }

這時候在項目中需要連接MySQL數據庫,在resources下添加jdbc.properties文件,內容如下:

jdbc_driverClassName=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/springtest
jdbc_username=root
jdbc_password=888888

在dispatcher-servlet.xml增加以下內容:

    ...
    <!-- 配置數據源 -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
                <!--要是有多個配置文件,只需在這里繼續添加即可 -->
            </list>
        </property>
    </bean>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName">
            <value>${jdbc_driverClassName}</value>
        </property>
        <property name="url">
            <value>${jdbc_url}</value>
        </property>
        <property name="username">
            <value>${jdbc_username}</value>
        </property>
        <property name="password">
            <value>${jdbc_password}</value>
        </property>
    </bean>
    <!-- 配置Mybatis的文件 ,mapperLocations配置**Mapper.xml文件位置,configLocation配置mybatis-config文件位置-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>
   ...

propertyConfigurer這個bean定義了配置文件路徑,dataSource這個bean找到配置文件就自動注入property。

在jdbc.properties中配置了jdbc_driverClassName=com.mysql.jdbc.Driver,這就是咱們連接MySQL的jar包包含的數據庫驅動,我們在前面pom.xml已經寫了一個MySQL的dependency,已經將該jar包下載下來了,現在就可以直接使用了,如果使用別的數據庫,那么就換成別的驅動包即可,相應的jdbc_driverClassName就需要修改。

sqlSessionFactory這個工廠類bean是mybatis推薦的使用方式,mapperLocations定義了mybatis的mapper xml文件的位置,可以看到我這是定義在resources下mapper目錄下的。

所以,我們需要在mapper目錄下新建一個UsersMapper.xml文件,內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.mapper.UsersMapper">
    <!--設置domain類和數據庫中表的字段一一對應,注意數據庫字段和domain類中的字段名稱不致,此處一定要!-->
    <resultMap id="BaseUsers" type="com.test.entity.Users">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="username" property="username" jdbcType="VARCHAR" />
        <result column="password" property="password" jdbcType="VARCHAR" />
    </resultMap>
    <!-- 查詢所有記錄 -->
    <select id="selectAllUsers" resultMap="BaseUsers">
        SELECT * FROM users
    </select>
    <!-- 查詢單個記錄 -->
    <select id="selectUsersByUsername" parameterType="java.lang.String"  resultMap="BaseUsers">
        SELECT * FROM users WHERE username=#{username}
    </select>
</mapper>

這樣就定義了數據庫表與entity類的映射關系,所謂ORM,就是對象於數據庫表映射的意思。完成了這個,我們就需要寫dao、service接口類和實現類了

dao接口類

package com.test.dao;

import com.test.entity.Users;

/**
 * Created by jeff on 2018/2/22.
 */
public interface UsersDao {
    Users getUsersByUsername(String username);
}

dao實現類

package com.test.dao.impl;

import com.test.dao.UsersDao;
import com.test.entity.Users;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;

/**
 * Created by jeff on 2018/2/22.
 */
@Repository
public class UsersDaoImpl extends SqlSessionDaoSupport implements UsersDao {
    @Resource
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        // TODO Auto-generated method stub
        super.setSqlSessionFactory(sqlSessionFactory);
    }
    @Override
    public Users getUsersByUsername(String username){
        return this.getSqlSession().selectOne("com.test.mapper.UsersMapper.selectUsersByUsername", username);
    }
}

service接口類

package com.test.service;

import com.test.entity.Users;

/**
 * Created by jeff on 2018/2/22.
 */
public interface UsersService {
    Users getUsersByUsername(String username);
}

service實現類

package com.test.service.impl;

import com.test.dao.UsersDao;
import com.test.entity.Users;
import com.test.service.UsersService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * Created by jeff on 2018/2/22.
 */
@Service
public class UsersServiceImpl implements UsersService {
    @Resource
    private UsersDao usersDao;
    @Override
    public Users getUsersByUsername(String username){
        return usersDao.getUsersByUsername(username);
    }
}

這時候IndexController需要修改為如下:

package com.test.controller;

import com.test.entity.Users;
import com.test.service.UsersService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.annotation.Resource;

/**
 * Created by jeff on 2018/2/13.
 */
@Controller
@RequestMapping("/")
public class IndexController {
    @Resource
    private UsersService usersService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String loginview(){
        return "loginview";
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(@ModelAttribute("username") String username, @ModelAttribute("password") String password){
        Users user = usersService.getUsersByUsername(username);
        if(user != null && user.getPassword().equals(password))
            return "index";
        return "loginview";
    }
}

這樣就完成了使用MyBatis連接數據庫查詢用戶信息跳轉index主頁的功能。

這里根據上面使用的Spring注解解釋一下,@Repository意思是倉庫、儲藏,這里就是持久層的意思,專門用來注解這是持久層bean,@Service意思就是服務層,專門用來注解服務層,還有一種注解是@Component,意思是組件,用來注解無法定義是服務層還是持久層的其他bean。這三個注解效果是一樣的,隨便換哪一個都是可以的,但為了方便閱讀和規范,請正確使用在對應的bean上。

@Controller的注解類似於struts的@Action注解,一般定義web層,直接與頁面交互。

@Resource注解標記了該屬性、方法需要被依賴注入。值得一提的是該注解並非Spring注解,而是J2EE的注解,只是Spring也支持使用該注解,Spring自己也實現了一個@AutoWired注解,兩個注解都能實現依賴注入,但使用起來有細微的區別,我通常使用@Resource方便一些。

最后,附上項目組織層級結構樹

由於知識水平有限,如有遺漏錯誤之處,請指正,非常感謝。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM