在工作中,博主是外包,项目上生产之后,甲方会以各种理由不让你轻易改动数据库(包括查询),虽然大家会理解这种行为,毕竟为了稳定,但一旦生产报错,问题的排查也会很艰难,这时,如果给自己的项目留一个能查询sql的功能,会变得异常实用。下面就是我的内容:
- JSP页面
<div id="ac">
<div>
<textarea id="sqlText" style="width:90%; padding:30px;" rows="20"></textarea>
<input type="button" value="确定" onclick="showData(this)"/>
</div>
<br/>
<br/>
<br/>
Result:
<br/>
<br/>
<div id="csrNodeTemp">
<table>
<tr style="background-color:#E0F2FE;">
<td> 1</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
<!-- 获得项目路径 -->
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<script type="text/javascript">
//刷新节点数据
function showData(obj){
var sData = $("#sqlText").val();
var randomnumber = Math.floor(Math.random()*100000);
$.ajax({
type:"get",
data:{
randomnumber:randomnumber,
sqlStr:sData
},
url:"${ctx}/common/querySyn/querySqlInfo",
async:true,
dataType:"text",
succsess:function(data){
$("#csrNodeTemp").html(data);
}
});
}
</script>
页面比较Low,仅仅是一个输入sql语句的textarea以及显示结果的table,输入sql语句后,点击确定按钮,执行sql(注意:sql语句末尾不用加";")。
- Controller
package cn.com.git.mar.intf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.thinkee.common.web.controller.BaseController;
import org.apache.commons.lang3.StringUtils;
@Controller
@RequestMapping(value="common/querySyn")
public class SynQueryController extends BaseController{
@Autowired
private IQueryDataService queryDataService;
@RequestMapping(method=RequestMethod.GET,value="querySqlInfo")
@ResponseBody
public Object querySqlInfo(String sqlStr) throws Exception{
String result = "";
if(StringUtils.isNotEmpty(sqlStr)){
try{
result = queryDataService.querySQLHTMLResult(sqlStr);
}catch(Exception e){
result = e.getMessage();
}
}
return result;
}
@RequestMapping(method=RequestMethod.GET,value="showPage")
public ModelAndView showPage(){
ModelAndView m = new ModelAndView();
m.setViewName("report/report_query");
return m;
}
}
- Service
package cn.com.git.mar.intf;
public interface IQueryDataService {
public String querySQLHTMLResult(String sql) throws Exception;
}
package cn.com.git.mar.intf;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class IQueryDataServiceImpl implements IQueryDataService {
@Autowired
private JdbcTemplate jdbcTemplate;
private static String PREFIX = "<table>";
private static String POSTFIX = "</table>";
@Override
public String querySQLHTMLResult(String sql) throws Exception {
Connection conn = null;
PreparedStatement ps = null;
try{
conn = jdbcTemplate.getDataSource().getConnection();
if(sql.toUpperCase().startsWith("SELECT")){
sql = checkQuerySql(sql);
ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int colNum = metaData.getColumnCount();
//填充表头
StringBuffer strTitle = new StringBuffer();
strTitle.append("<tr align=\"center\" style=\"background-color:#E0F2FE;\"><td></td>");
for(int i=1;i<=colNum;i++){
strTitle.append("<td>");
strTitle.append(metaData.getColumnClassName(i));
strTitle.append("</td>");
}
strTitle.append("</tr>");
//填充数据
int dataCount = 0;
StringBuffer strData = new StringBuffer();
while(rs.next()){
dataCount++;
strData.append("<tr align=\"center\">");
strData.append("<td>" + dataCount + "</td>");
for(int i=1;i<=colNum;i++){
if(rs.getObject(i)==null){
strData.append("<td></td>");
}else{
//标题名不超过40个字符
String data = rs.getObject(i).toString();
if(data.length() > 40){
data = data.substring(0,39);
}else{
data = data.toString();
}
strData.append("<td><label title='" + rs.getObject(i) + "'>" + data + "<label></td>");
}
}
strData.append("</tr>");
}
return PREFIX + strTitle.toString() + strData.toString() + POSTFIX;
}else{
ps = conn.prepareStatement(sql);
int s = ps.executeUpdate();
return PREFIX + "<tr><td>执行成功,共影响行数:" + s + "</td></tr>" + POSTFIX;
}
}catch(Exception e){
throw e;
}
}
private String checkQuerySql(String sql) {
if(sql.toUpperCase().indexOf("ROWNUM")<0){
String sqlStr = "SELECT * FROM (" + sql + ") C WHERE ROWNUM<60";
return sqlStr;
}else{
return sql;
}
}
}
- 总结
代码都比较简单,但博主的代码在自己的项目里仅支持查询,一旦使用update等增删改类语句,虽然返回的结果是已修改,但数据库中并没有变动,且涉及到的表均被锁住,如果有阅读过的朋友知道如何修改请告知博主,博主将感激不尽
有兴趣的话可以看看我的私人博客,也可以关注我的公众号,说不定会有意外的惊喜。