当前位置:网站首页>JDBC quick start tutorial
JDBC quick start tutorial
2022-06-12 17:42:00 【*Night Star River】
primary coverage
- JDBC Use
- JDBC Tool class
- JDBC Control the transaction
Teaching objectives
- Able to understand JDBC The concept of
- Able to use DriverManager class
- Able to use Connection Interface
- Able to use Statement Interface
- Able to use ResultSet Interface
- Be able to say SQL Injection reason and solution
- Can pass PreparedStatement Complete the addition 、 Delete 、 Change 、 check
- Can finish PreparedStatement Transformation login case
JDBC
Concept
Java DataBase Connectivity Java Database connection , Java Language operation database
The essence
Actually, it's official (sun company ) A set of rules defined to operate all relational databases , Interface .
Each database manufacturer shall implement this set of interfaces , Provide database driver jar package .
We can use this interface (JDBC) Programming , The code that actually executes is the driver jar The implementation class in the package .
benefits
1) If a programmer wants to develop a program to access a database , Just call JDBC Interface , Don't worry about how classes are implemented .
2) Use the same set Java Code , With a few changes, you can access other JDBC Supported databases
Quick start
step
* step :
1. Import driver jar package mysql-connector-java-5.1.37-bin.jar
1. Create... In the project libs Catalog
2. Copy mysql-connector-java-5.1.37-bin.jar To the project libs Under the table of contents
3. stay libs Select the... To be added under the directory jar package , And then right-click -->Bulid Path-->Add to Build Path
2. Registration drive
3. Get database connection object Connection
4. Definition sql
5. Access to perform sql Object of statement Statement
6. perform sql, Accept the return result
7. Processing results
8. Release resources
Explain each core object in detail
1. DriverManager
DriverManager: Drive management objects
* function :
1. Registration drive : Tell the program which database driver to use jar
static void registerDriver(Driver driver) : Register with given driver DriverManager .
Write code using : Class.forName("com.mysql.jdbc.Driver");
Discover by looking at the source code : stay com.mysql.jdbc.Driver Class has static code blocks
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
Be careful :mysql5 After the drive jar Packages can omit the steps of registering drivers .
2. Get database connection :
* Method :static Connection getConnection(String url, String user, String password)
* Parameters :
* url: Specify the path of the connection
* grammar :jdbc:mysql://ip Address ( domain name ): Port number / Database name
* Example :jdbc:mysql://localhost:3306/db3
* details : If the connection is local mysql The server , also mysql The default port for the service is 3306, be url I could just write it as :jdbc:mysql:/// Database name
* user: user name
* password: password
2. Connection
Connection: Database connection object
1. function :
1. Access to perform sql The object of
* Statement createStatement()
* PreparedStatement prepareStatement(String sql)
2. Manage affairs :
* Open transaction :setAutoCommit(boolean autoCommit) : Call this method to set the parameter to false, That is, start the transaction
* Commit transaction :commit()
* Roll back the transaction :rollback()
3. Statement
1. perform sql
1. boolean execute(String sql) : You can do whatever you want sql understand
2. int executeUpdate(String sql) : perform DML(insert、update、delete) sentence 、DDL(create,alter、drop) sentence
* Return value : Number of rows affected , It can be judged by the number of rows affected DML Is the statement executed successfully Return value >0 Then the execution is successful , conversely , The failure .
3. ResultSet executeQuery(String sql) : perform DQL(select) sentence
practice :
1.student surface Add a record
2. student surface Modify the record
3. student surface Delete a record
// The load driver , Connect to database , Release resources
package com.zhibang.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/** * The load driver , Connect to database , Release resources * @author Rain falls on the stars * */
public class Utils {
private static String driver = "com.mysql.jdbc.Driver";// Load the driver package
private static String url = "jdbc:mysql://localhost:3306/girls";// Connect to database localhost For the local id girls Name the database table
private static String urname = "root";// user name
private static String pass = "3306";// password
/** * Load the driver package */
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** * Connect to database * @return */
public static Connection getConnection() {
Connection con = null;
try {
con = DriverManager.getConnection(url,urname,pass);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return con;
}
/** * Release Connection,PreparedStatement,ResultSet resources * @param con * @param ps * @param rst */
public static void close(Connection con,PreparedStatement ps,ResultSet res) {
try {
if(con!=null) {
con.close();
}
if(ps!=null) {
ps.close();
}
if(res!=null) {
res.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** * Release Connection,PreparedStatement resources * @param con * @param ps */
public static void close_1(Connection con,PreparedStatement ps) {
try {
if(con!=null) {
con.close();
}
if(ps!=null) {
ps.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// Students
package com.zhibang.student;
/** * Table data * @author Rain falls on the stars * */
public class student {
private int id;// Student number
private String uname;// user name
private String psw;// password
public student() {
}
public student(int id2, String uname, String psw) {
super();
this.id = id2;
this.uname = uname;
this.psw = psw;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPsw() {
return psw;
}
public void setPsw(String psw) {
this.psw = psw;
}
@Override
public String toString() {
return "student [id=" + id + ", uname=" + uname + ", psw=" + psw + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((psw == null) ? 0 : psw.hashCode());
result = prime * result + ((uname == null) ? 0 : uname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
student other = (student) obj;
if (id != other.id)
return false;
if (psw == null) {
if (other.psw != null)
return false;
} else if (!psw.equals(other.psw))
return false;
if (uname == null) {
if (other.uname != null)
return false;
} else if (!uname.equals(other.uname))
return false;
return true;
}
}
- student surface Add a record
// Pick up your golden hand and listen to the class while realizing
public static int getinsert(student st) {
String sql = "INSERT INTO admin(`username`,`password`) VALUES ('"+ st.getUname() +"','"+ st.getPsw() +"')";
int n = 0;
try {
con = Utils.getConnection();
ps = con.prepareStatement(sql);
n = ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
Utils.close_1(con, ps);
}
return n;
}
- student surface Modify the record
// Pick up your golden hand and listen to the class while realizing
public static int getupdate(student st) {
String sql = "UPDATE admin SET `password`='"+ st.getPsw() +"' WHERE id="+ st.getId() +"";
int n = 0;
try {
con = Utils.getConnection();
ps = con.prepareStatement(sql);
n = ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
Utils.close_1(con, ps);
}
return n;
}
- student surface Delete a record
// Pick up your golden hand and listen to the class while realizing
public static int getdelect(student st) {
String sql = "DELETE FROM admin WHERE id="+ st.getId() +"";
int n = 0;
try {
con = Utils.getConnection();
ps = con.prepareStatement(sql);
n = ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
Utils.close_1(con, ps);
}
return n;
}
- perform DDL sentence
// Pick up your golden hand and listen to the class while realizing
// add to
student st = new student();
st.setUname("ccc");
st.setPsw("244542");
int n = UserDao.getinsert(st);
if(n>0) {
System.out.println(" Submit successfully ");
}else {
System.out.println(" Submit failed ");
}
// modify
student st = new student();
st.setId(1);
st.setPsw("2113");
int n = UserDao.getupdate(st);
if(n>0) {
System.out.println(" Submit successfully ");
}else {
System.out.println(" Submit failed ");
}
// Delete
student st = new student();
st.setId(6);
int n = UserDao.getdelect(st);
if(n>0) {
System.out.println(" Submit successfully ");
}else {
System.out.println(" Submit failed ");
}
4. ResultSet
* boolean next(): Move the cursor down one line , Determine whether the current line is the end of the last line ( Is there any data ), If it is , Then return to false, If not, return true
* getXxx( Parameters ): get data
* Xxx: Representative data type Such as : int getInt() , String getString()
* Parameters :
1. int: Represents the number of the column , from 1 Start Such as : getString(1)
2. String: Name of representative column . Such as : getDouble("balance")
* Be careful :
* Use steps :
1. Move the cursor down one line
2. Judge whether there is data
3. get data
// Loop to determine whether the cursor is at the end of the last line .
while(rs.next()){
// get data
//6.2 get data
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble(3);
System.out.println(id + "---" + name + "---" + balance);
}
* practice :
* Define a method , Inquire about student The table's data encapsulates it as an object , Then load the collection , return .
1. Definition student class
2. Define methods public List<student> findAll(){}
3. Implementation method select * from student;
// The load driver , Connect to database , Release resources
package com.zhibang.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/** * The load driver , Connect to database , Release resources * @author Rain falls on the stars * */
public class Utils {
private static String driver = "com.mysql.jdbc.Driver";// Load the driver package
private static String url = "jdbc:mysql://localhost:3306/girls";// Connect to database localhost For the local id girls Name the database table
private static String urname = "root";// user name
private static String pass = "3306";// password
/** * Load the driver package */
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** * Connect to database * @return */
public static Connection getConnection() {
Connection con = null;
try {
con = DriverManager.getConnection(url,urname,pass);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return con;
}
/** * Release Connection,PreparedStatement,ResultSet resources * @param con * @param ps * @param rst */
public static void close(Connection con,PreparedStatement ps,ResultSet res) {
try {
if(con!=null) {
con.close();
}
if(ps!=null) {
ps.close();
}
if(res!=null) {
res.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** * Release Connection,PreparedStatement resources * @param con * @param ps */
public static void close_1(Connection con,PreparedStatement ps) {
try {
if(con!=null) {
con.close();
}
if(ps!=null) {
ps.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Implementation code (student class ):
// Pick up your golden hand and listen to the class while realizing
package com.zhibang.student;
/** * Table data * @author Rain falls on the stars * */
public class student {
private int id;// Student number
private String uname;// user name
private String psw;// password
public student() {
}
public student(int id2, String uname, String psw) {
super();
this.id = id2;
this.uname = uname;
this.psw = psw;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPsw() {
return psw;
}
public void setPsw(String psw) {
this.psw = psw;
}
@Override
public String toString() {
return "student [id=" + id + ", uname=" + uname + ", psw=" + psw + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((psw == null) ? 0 : psw.hashCode());
result = prime * result + ((uname == null) ? 0 : uname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
student other = (student) obj;
if (id != other.id)
return false;
if (psw == null) {
if (other.psw != null)
return false;
} else if (!psw.equals(other.psw))
return false;
if (uname == null) {
if (other.uname != null)
return false;
} else if (!uname.equals(other.uname))
return false;
return true;
}
}
Implementation code ( Reading class )
// Pick up your golden hand and listen to the class while realizing
public static List<student> getselect() {
String sql="select * from student";
List<student> li = new ArrayList<student>();
try {
con = Utils.getConnection();
ps = con.prepareStatement(sql);
res = ps.executeQuery();
while (res.next()) {
int id = res.getInt("id");
String uname = res.getNString("username");
String psw = res.getString("password");
li.add(new student(id, uname, psw));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
Utils.close(con, ps, res);
}
return li;
}
5. PreparedStatement
1. SQL Injection problem : In splicing sql when , Somewhat sql Special keywords participate in string splicing . Can cause security problems
1. Input users casually , Input password :a' or 'a' = 'a
2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
2. solve sql Injection problem : Use PreparedStatement Object to solve
3. precompiled SQL: Parameters use ? As placeholder
4. step :
1. Import driver jar package mysql-connector-java-5.1.37-bin.jar
2. Registration drive
3. Get database connection object Connection
4. Definition sql
* Be careful :sql Parameter usage of ? As placeholder . Such as :select * from user where username = ? and password = ?;
5. Access to perform sql Object of statement PreparedStatement Connection.prepareStatement(String sql)
6. to ? assignment :
* Method : setXxx( Parameters 1, Parameters 2)
* Parameters 1:? Location number of from 1 Start
* Parameters 2:? Value
7. perform sql, Accept the return result , There is no need to pass on sql sentence
8. Processing results
9. Release resources
5. Be careful : It will be used later PreparedStatement To complete all operations of addition, deletion, modification and query
1. Can prevent SQL Inject
2. More efficient
extract JDBC Tool class : JDBCUtils
explain
* Purpose : Simplify writing
* analysis :
1. Registration driver is also called extraction
2. Extract a method to get the connection object
* demand : Don't want to pass parameters ( trouble ), We also need to ensure the universality of tool class .
* solve : The configuration file
jdbc.properties
url=
user=
password=
3. Extract a method to release resources
Concrete realization
Registration drive
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/** * File reading , You only need to read it once to get these values . Use static code blocks */
static{
// Read resource file , Get value .
try {
//1. establish Properties Collection classes .
Properties pro = new Properties();
// obtain src The way of files under the path --->ClassLoader Class loader
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
System.out.println(path);
//2. Load the file
// pro.load(new FileReader("E:\\eclipse-workspace\\First\\src\\jdbc.properties"));
pro.load(new FileReader(path));
//3. get data , assignment
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4. Registration drive
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
// IO Stream loading properties file
InputStream inputStream = ClassLoader.getSystemResourceAsStream("/jdbc.properties");
// InputStream inputStream = LoadPropertiesFile.class.getResourceAsStream("/jdbc.properties");
Properties prop = new Properties();
prop.load(inputStream);
Extract a method to get the connection object
/** * Get the connection * @return Connection object */
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
/** * Release resources * @param stmt * @param conn */
public static void close(Statement stmt,Connection conn){
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Extract a method to release resources
/** * Release resources * @param stmt * @param conn */
public static void close(ResultSet rs,Statement stmt, Connection conn){
if( rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
practice
* practice :
* demand :
1. Enter the user name and password through the keyboard
2. Determine whether the user has successfully logged in
* select * from user where username = "" and password = "";
* If this sql There are query results , The successful , conversely , The failure
* step :
1. Create database tables user
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32),
PASSWORD VARCHAR(32)
);
INSERT INTO USER VALUES(NULL,'zhangsan','123');
INSERT INTO USER VALUES(NULL,'lisi','234');
2. Code implementation
Code implementation
// The load driver , Connect to database , Release resources
package com.zhibang.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/** * The load driver , Connect to database , Release resources * @author Rain falls on the stars * */
public class Utils {
private static String driver = "com.mysql.jdbc.Driver";// Load the driver package
private static String url = "jdbc:mysql://localhost:3306/girls";// Connect to database localhost For the local id girls Name the database table
private static String urname = "root";// user name
private static String pass = "3306";// password
/** * Load the driver package */
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** * Connect to database * @return */
public static Connection getConnection() {
Connection con = null;
try {
con = DriverManager.getConnection(url,urname,pass);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return con;
}
/** * Release Connection,PreparedStatement,ResultSet resources * @param con * @param ps * @param rst */
public static void close(Connection con,PreparedStatement ps,ResultSet res) {
try {
if(con!=null) {
con.close();
}
if(ps!=null) {
ps.close();
}
if(res!=null) {
res.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/** * Release Connection,PreparedStatement resources * @param con * @param ps */
public static void close_1(Connection con,PreparedStatement ps) {
try {
if(con!=null) {
con.close();
}
if(ps!=null) {
ps.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// According to user name and password
public static boolean getnamepass(String name,String pass) {
if(name==null&&pass==null) {
return false;
}
try {
con = Utils.getConnection();
// String sql = "select * from admin where username='"+ name +"' and password='"+ pass +"'";
// prevent sql Inject
String sql = "select * from admin where username=? and password=?";
ps = con.prepareStatement(sql);
ps.setString(1, name);
ps.setString(2, pass);
res = ps.executeQuery();
return res.next();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
Utils.close(con, ps, res);
}
return false;
}
// Implementation class
Scanner sc = new Scanner(System.in);
System.out.println(" Please enter a user name :");
String name = sc.next();
System.out.println(" Please input a password :");
String pass = sc.next();
boolean getnamepass = UserDao.getnamepass(name, pass);
if(getnamepass) {
System.out.println(" Login successful !!!");
}else {
System.out.println(" Wrong user name or password !!!");
}
JDBC Control the transaction
explain
1. Business : A business operation with multiple steps . If the business operation is managed by a transaction , Then these multiple steps will either succeed at the same time , Or fail at the same time .
2. operation :
1. Open transaction
2. Commit transaction
3. Roll back the transaction
3. Use Connection Object to manage affairs
* Open transaction :setAutoCommit(boolean autoCommit) : Call this method to set the parameter to false, That is, start the transaction
* In execution sql Before opening the transaction
* Commit transaction :commit()
* When all sql All commit transactions are completed
* Roll back the transaction :rollback()
* stay catch Rollback transaction
Realization
public class AccountDao {
/* * Modify the balance of the specified user */
public void updateBalance(Connection con, String name,double balance) {
try {
String sql = "UPDATE account SET balance=balance+? WHERE name=?";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setDouble(1,balance);
pstmt.setString(2,name);
pstmt.executeUpdate();
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class Demo1 {
/* * Demonstrate transfer method * All right Connect The operations of Service Layer * Put all the connection The operation of is hidden , This requires the use of custom gadgets (day19_1) * */
public void transferAccounts(String from,String to,double money) {
// Operations on transactions
Connection con = null;
try{
con = JdbcUtils.getConnection();
con.setAutoCommit(false);
AccountDao dao = new AccountDao();
dao.updateBalance(con,from,-money);// to from Less the corresponding amount
if (true){
throw new RuntimeException(" sorry , Transfer failure ");
}
dao.updateBalance(con,to,+money);// to to Add the corresponding amount
// Commit transaction
con.commit();
} catch (Exception e) {
try {
con.rollback();
} catch (SQLException e1) {
e.printStackTrace();
}
throw new RuntimeException(e);
}
}
@Test
public void fun1() {
transferAccounts("zs","ls",100);
}
}
}
dao.updateBalance(con,to,+money);// to to Add the corresponding amount
// Commit transaction
con.commit();
} catch (Exception e) {
try {
con.rollback();
} catch (SQLException e1) {
e.printStackTrace();
}
throw new RuntimeException(e);
}
}
@Test
public void fun1() {
transferAccounts("zs","ls",100);
}
}
边栏推荐
- Some introduction to FPC flexible circuit board design
- Implementation of asynchronous query of Flink dimension table and troubleshooting
- 有关cookie的用法介绍
- SSM集成FreeMarker以及常用语法
- C# 业务流水号规则生成组件
- EasyCode模板
- (5) Outputs and outputs
- Hangzhou AI developer meetup registration opens!
- The R language uses the aggregate The plot function visualizes the summary statistical information of each subset (visualization is based on the probability value and its 95% confidence interval of th
- Vulnhub[DC3]
猜你喜欢
C#操作数据库增查业务数据值内容案例学校表
Vulnhub[DC3]
Use GCC's PGO (profile guided optimization) to optimize the entire system
Yyds dry goods inventory leetcode question set 911 - 920
Some introduction to FPC flexible circuit board design
MySQL transaction introduction and transaction isolation level
Cesium抛物线方程
Introduction to several common functions of fiddler packet capturing (stop packet capturing, clear session window contents, filter requests, decode, set breakpoints...)
Detailed explanation of shardingjdbc database and table
Application case of smart micro 32-bit MCU for server application cooling control
随机推荐
TensorFlow求梯度时提示TypeError: unsupported operand type(s) for *: ‘float‘ and ‘NoneType‘
Reconnaître l'originalité de la fonction
118. 杨辉三角(动态规划)
73. matrix zeroing (marking method)
認識函數原創
错误记录:IllegalStateException: Optional int parameter ‘xxxx‘ is
数据库SQL操作基础
Risc-v ide mounriver studio v1.60 update point introduction
1.5 什么是架构师(连载)
Li Kou today's question 926 Flip string to monotonic increment
Interesting LD_ PRELOAD
MySQL transaction introduction and transaction isolation level
5、Embedding
MIPS 通用寄存器 + 指令
Quick start sweep crawler framework
三代DRI的变化
Qiushengchang: Practice of oppo commercial data system construction
Tensorflow prompts typeerror: unsupported operand type (s) for *: 'float' and 'nonetype‘
Kill program errors in the cradle with spotbugs
New media operation material website sharing enables you to create current affairs with half the effort