Solving errors in web projects, java.io.FileNotFoundException: druid.properties (the system cannot find the specified file); [spring factory decoupling development]

When using Tomcat9.0, spring5.0 framework original factory class decoupling, druid-1.0.9jar version, JDK9, MSQL8 version database to simulate web page login case, an error message that the druid.properties file cannot be found appears, the details are as follows [Case code posted at the end];

Normally speaking, the configuration file is placed under the src directory, and then just copy the relative path, but Alibaba is anti-human;

Running error, web browser null pointer, in IDEA:

The solution is to copy the full path to resolve the error;

Run it again and it runs smoothly;

Another solution is to use a class loader:

FileInputStream fis = new FileInputStream(JdbcUtils.class.getResource("/").getPath() + "druid.properties");
Properties p = new Properties();
p.load(fis);

The project structure is as follows:

① First jar package [in lib], and configuration file [under src];

② Write case page log.html;

③ Develop utils tool classes [including obtaining jdbcTemplate and obtaining BeanFactory of beans]. This test used c3p0 and druid for testing;

④Develop bean [corresponds to the table in the database], dao layer, daoImpl layer, service layer, serviceImpl layer [needs decoupling], servlet [decoupling]

⑤ Test [Spring’s xml configuration complete login case CRUD has been written and you can see it yourself in the bolg]

Configuration file, according to the project structure [not explained one by one]:

tUserDao=com.baidu.daoImpl.TUserDaoImpl
tUserService=com.baidu.serviceImpl.TUserServiceImpl

<?xml version="1.0" encoding="UTF-8" ?>

<c3p0-config>
    <!-- Default configuration, the c3p0 framework loads this default configuration by default -->
    <default-config>
        <!-- Configure the four basic properties of JDBC -->
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/reba?serverTimezone=UTC & amp;amp;characterEncoding=utf-8 & amp;amp;useSSL=false</property>
        <property name="user">root</property>
        <property name="password">root</property>
    </default-config>
    <!-- You can customize the configuration, give this configuration a name, and c3p0 specifies the name to load the configuration -->
    <named-config name="hello">
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/reba?serverTimezone=UTC & amp;amp;characterEncoding=utf-8 & amp;amp;useSSL=false</property>
        <property name="user">root</property>
        <property name="password">root</property>
    </named-config>
</c3p0-config>
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/reba?serverTimezone=UTC & amp;characterEncoding=UTF-8 & amp;useSSL=false
username=root
password=root

filters=stat
initialSize=2
maxActive=300
maxWait=60000
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 1
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
poolPreparedStatements=false
maxPoolPreparedStatementPerConnectionSize=200
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/reba?serverTimezone=UTC & amp;characterEncoding=UTF-8 & amp;useSSL=false
jdbc.username=root
jdbc.password=root

The entity bean class can correspond to the database. The database table is as follows [id int, userName varchar, password varchar]:

The action in the page form is the urlParttens of the servlet;

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* be placed first, and any other content *must* follow them! -->
    <!-- viewport: Viewport, supports responsive layout.
    width: The initial width is the same as the width of the device
    initial-scale: initial scaling ratio, 1:1
    -->
    <!-- 1. Import the css style file in bootstrap -->
    <!-- 2. Import jQuery framework -->
    <!-- 3. Import the bootstrap js file -->
    <!-- 4. Import jQuery framework plug-in -->
    <title>Bootstrap 101 Template</title>
    <link href="config/css/bootstrap.min.css" rel="stylesheet">
    <script src="config/jquery-3.3.1.min.js"></script>
    <script src="config/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container " style="width: 300px">
    <div class="row" style="text-align: center">
        <!--action specifies the url of the browser-->
        <form action="/log" method="post" class="form-group">
            <input type="text" placeholder="Please enter user name" name="userName" class="form-control"><br/>
            <input type="text" placeholder="Please enter password" name="password" class="form-control"><br/>
            <input type="submit" value="Login" class="btn btn-sm btn-primary btn-block">
        </form>
    </div>
</div>
</body>
</html>

Effect:

Develop utils tool classes;

beans factory class;

package com.baidu.utils;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.ResourceBundle;
/**
 * @auther SyntacticSugar
 * @data 2018/9/29 0029 10:50 pm
 */
public class BeanFactory {
    private static ResourceBundle rb = ResourceBundle.getBundle("beans");
    private static HashMap<String, Object> map = new HashMap<>();
    static {
        try {
            Enumeration<String> keys = rb.getKeys();
            while (keys.hasMoreElements()) {
                String key = keys.nextElement();
                String value = rb.getString(key); //Get the full path of value from beans.properties
                Object o = Class.forName(value).getDeclaredConstructor().newInstance();
                map.put(key, o);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * Get bean
     * @param beanName
     * @return
     */
    public static Object getBeans(String beanName) {
        return map.get(beanName);
    }
}

Connect data and get template;

package com.baidu.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

/**
 * @auther SyntacticSugar
 * @data 2018/9/29 0029 10:22 pm
 */
public class JdbcUtils {
    private static JdbcTemplate template;
    private static Connection conn;
    private static PreparedStatement statement;
    private static ResultSet res;
    /**
     * Get template
     */
    public static JdbcTemplate getJdbcTemplate() {
        try { //druid
            FileInputStream fis = new FileInputStream(JdbcUtils.class.getResource("/").getPath() + "druid.properties");
            Properties p = new Properties();
            p.load(fis);
// p.load(new FileReader("druid.properties")); // If an error occurs, the file cannot be loaded. You can use the absolute path.
            DataSource dataSource = DruidDataSourceFactory.createDataSource(p);

            //c3p0 connects to the database and obtains jdbcTemplate
// ComboPooledDataSource dataSource = new ComboPooledDataSource();
            template = new JdbcTemplate(dataSource);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return template;
    }

    /**
     * Release resources
     * @param res
     * @param statement
     * @param conn
     */
    public static void release(ResultSet res, PreparedStatement statement, Connection conn) {
        try {
            if (res != null) {
                res.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

dao layer [Explanation: Use the query method of template to query because userName & amp;password may exist in multiple databases. If you query by id, you can use queryForObject, the uniqueness of id; in addition, when transmitting data You can encapsulate userName & password into a TUser object from the dao layer, so that you can directly pass a TUser object when passing parameters];

package com.baidu.dao;
import com.baidu.Beans.TUser;
import java.util.List;
/**
 * @auther SyntacticSugar
 * @data 2018/9/29 0029 10:17 pm
 */
public interface TUserDao {
    //Query by userName password
    List<TUser> findTUserByNameAndPsw(String userName,String password);
}

daoReality class;

package com.baidu.daoImpl;
import com.baidu.Beans.TUser;
import com.baidu.dao.TUserDao;
import com.baidu.utils.JdbcUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
/**
 * @auther SyntacticSugar
 * @data 2018/9/29 0029 10:43 pm
 */
public class TUserDaoImpl implements TUserDao {
    @Override
    public List<TUser> findTUserByNameAndPsw(String userName, String password) {
        JdbcTemplate template = JdbcUtils.getJdbcTemplate();
        String sql="select * from t_user where userName=? and password=?";
        List<TUser> list = template.query(sql, new BeanPropertyRowMapper<TUser>(TUser.class), userName, password);
        return list;
    }
}

service layer;

package com.baidu.service;
public interface TUserService {
    Boolean login(String userName, String password);
}

Service implementation class [This layer is decoupled. Because the daoImpl class is used, new is generally used, and the coupling is high. AOP is used to reduce the coupling. Here, spring’s old factory class is used to obtain the full definition of the bean. Name, create an object of the daoImpl class through reflection, thereby reducing the coupling between layers; PS: Reducing coupling does not mean there is no coupling, but changing the class, etc., is changed in the configuration file without touching the java code. Of course, compared with Regarding xml and annotation methods, this method is too low and is only used for understanding and learning];

Using the interface to receive daoImpl reflects the idea of interface-oriented programming [ps: Bingao, no one uses this for decoupling development using annotations];

package com.baidu.serviceImpl;
import com.baidu.Beans.TUser;
import com.baidu.dao.TUserDao;
import com.baidu.daoImpl.TUserDaoImpl;
import com.baidu.service.TUserService;
import com.baidu.utils.BeanFactory;
import java.util.List;
/**
 * @auther SyntacticSugar
 * @data 2018/9/29 0029 10:47 pm
 */
public class TUserServiceImpl implements TUserService {
    @Override
    public Boolean login(String userName, String password) {
        TUserDao tUserDao = (TUserDaoImpl) BeanFactory.getBeans("tUserDao");//Use the interface to receive
// TUserDaoImpl tUserDao = new TUserDaoImpl();
        List<TUser> list = tUserDao.findTUserByNameAndPsw(userName, password);
        //Process the list and return TUser
        if(list.size()==0){
            return false;
        }else {
            return true;
        }
    }
}

Servlet, if the login is successful, it will jump to Baidu, otherwise, the login will not be successful on the page;

package com.baidu.session;
import com.baidu.Beans.TUser;
import com.baidu.service.TUserService;
import com.baidu.serviceImpl.TUserServiceImpl;
import com.baidu.utils.BeanFactory;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet(name = "Log", urlPatterns = "/log")
public class Log extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);//
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //
        String userName = request.getParameter("userName");
        String password = request.getParameter("password");
        //Call serviceImpl
        TUserService o = (TUserServiceImpl) BeanFactory.getBeans("tUserService");//Use the interface to receive

// TUserServiceImpl o = new TUserServiceImpl();
        Boolean login = o.login(userName, password);
        //
        if (login) { //Login successful, redirect to Baidu
            System.out.println("ok");
        response.sendRedirect("http://www.baidu.com");
        }else { //Failed, forward to jsp
            System.out.println("Login failed");
            request.setAttribute("info","Login failed" );
            request.getRequestDispatcher("log.html").forward(request,response);
        }
    }
}

Click to start Tomcat, the page will load automatically, enter userName & password for testing;

Here I will talk about the configuration list that needs to be configured in web.xml; I won’t go into details after pasting the configuration;

<welcome-file-list>
    <welcome-file>log.html</welcome-file>
    <welcome-file>product.html</welcome-file>
    <welcome-file>regist.html</welcome-file>
    <welcome-file>login.html</welcome-file>
</welcome-file-list>

It started running. The key point is that after druid.properties was deployed in Tomcat, an error was reported that the file could not be found;