2017 开发Fix集锦 - yiyixiaozhi/readingNotes GitHub Wiki
title: 开发Fix集锦 date: 2017-10-2 23:28:11 description: 17年开发过程中遇到的一些小问题的解决 categories:
- 开发 tags:
配置ssh链接,jdk,hadoop,Samba
- 修改终端字体大小
sudo dpky-reconfigure console-setup
- 第一次root用户解锁操作
- 修改root密码
sudo passwd root
- 用户注销
logout
- ubuntu16.04切换到root用户登录
su root
- 以root用户进行登录
- who命令来查看是谁登录。
- 关闭Linux防火墙
ufw disable
- 卸载iptables组件
apt-get remove iptables
- 安装vim
apt-get install vim
- Hostname主机
vim /etc/hosts
- ssh工具:
apt-get install openssh-server
- 启动ssh服务:
/etc/init.d/ssh start
- 查看是否服务已经启动:
ps -e | grep sshd
- 解决默认不能root用户登录使用ssh的问题:
vim /etc/ssh/sshd_config
随后修改PermitRootLogin,将内容设置为yes
- 安装
apt-get install vsftpd
- 修改默认ftp用户的密码
passwd ftp
ftp完成后,会自动创建目录 /srv/ftp,修改权限
chmod 777 /srv/ftp
如果要ftp正常工作,修改配置文件
vim /etc/vsftpd.conf
修改如下参数:
anonymous_enable NO //不允许匿名登录
...
local_enable YES //允许本地用户登录
...
write_enable=YES //用户具有写权限
...
chroot_local_user=YES //是否将所有用户限制在主目录
...
chroot_list_enable=YES //是否启动限制用户的名单
- 定义名单设置的目录(名单中可以设置多个账号)
chroot_list_file=/etc/vsftpd.chroot_list
- 增加一个服务配置 pam-service_name=vsftpd ,注意文件中不能存在此条信息的重复数据(我新增了一条,踩了个坑)。
- 增加一个新的文件,写上一个用户
vim /etc/vsftpd.chroot_list
- 在第一行写上ftp,表示新增一个用户
- 修改 vim /etc/pam.d/vsftpd,注释掉以下内容:
# auth required pam_shells.so
- 启动服务
service vsftpd start
- 下载Linux版本jdk.
- XShell使用rz命令传到服务器
- 解压
root@ubuntu:/home/bianxh/Downloads# tar xzvf jdk-8u111-linux-x64.tar.gz -C /usr/local
- 打开环境文件进行配置:
vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.8.0_111
export PATH=$PATH:$JAVA_HOME/bin:
export CLASS_PATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
- 让配置立刻生效
source /etc/profile
- 测试下是否生效成功
root@ubuntu:/usr/local/jdk1.8.0_111# java -version
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
- 上传Hadoop文件并解压缩
root@ubuntu:/home/bianxh/Downloads# tar xzvf hadoop-2.6.0.tar.gz -C /usr/local
- 配置环境变量,修改/etc/profile
export HADOOP_HOME=/usr/local/hadoop-2.6.0
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:
- 让配置立刻生效
source /etc/profile
- hadoop依赖jdk
root@ubuntu:/usr/local/hadoop-2.6.0/etc/hadoop# vim hadoop-env.sh
#export JAVA_HOME=${JAVA_HOME}
export JAVA_HOME=/usr/local/jdk1.8.0_111
Linux常用命令
- 设置当前系统时间命令示例:
$ date –set “10/15/2009 20:18”
- 递归解压bz2g格式压缩包示例:
tar -jxvf cygwin.tar.bz2 -C 指定目录
- Samba服务器文件夹权限分配实例(修改/etc/samba/smb.conf):
[bianxh]
comment = File Share of bianxh
browseable = yes
path = /home/bianxh/
writable = yes
create mask = 777
valid users = public bianxh
directory mask = 777
available = yes
Mac下安装brew、Redis、zookeeper过程中踩过的坑。
Mac serria偏好设置找到“打开任意来源”命令
$ sudo spctl --master-disable
重建MAC的右键打开方式列表 Mac上选中一个文件点击右键会有一个“Open With”菜单,如果你装过多个虚拟机等,这个菜单会出现很多windows系统的程序,从而使这个菜单十分混乱,可以使用以下命令行来清除所有的重复项。
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain user;killall Finder;echo “Open With has been rebuilt, Finder will relaunch“
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install\"
安装下载工具
brew install wget
$ wget http://download.redis.io/releases/redis-3.0.7.tar.gz
$ tar xzf redis-3.0.7.tar.gz
$ cd redis-3.0.7
$ make
启动redis
$ src/redis-server redis.conf
连接上以后,关闭redis
$ src/redis-cli
$ 127.0.0.1:6379> SHUTDOWN
测试redis
$ src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"
# Mac OS命令行下使用SublimeText打开文本文件
打开用户配置文件
vim ~/.bash_profile
添加如下alias
alias subl="'/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl'"
alias ll='ls -al'
如果不添加别名,也可以选择将路径添加到环境变量下。这里的路径根据实际情况可能会有所不同。
wq保存后回到命令行执行以下命令使其生效:
source ~/.bash_profile
命令行使用,这里我们假设在命令行用SublimeText打开.bash_profile,则执行如下:
subl ~/.bash_profile
$brew install zookeeper
启动服务
$ sudo zkServer start
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Starting zookeeper ... STARTED
在MAC下需要用sudo命令来启动此服务,否则会失败。
查看zookeeper运行及状态
$ zkServer status
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Mode: standalone
$zkCli
Connecting to localhost:2181
停止服务
$ zkServer stop
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Stopping zookeeper ... STOPPED
$ subl ~/.bash_profile
export JAMES_SRC_HOME=/usr/local/james-project/james-project
安装maven,参考教程
$ brew install maven
默认安装位置是
$ /usr/local/Cellar/maven/3.3.9
Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-resources-plugin:jar:2.6
解决方法:
1、查看windows -> Preferences -> maven 的settings.xml文件中.m2的位置
2、然后将.m2/repository/org/apache/maven/plugins目录下的文件夹全部删除
3、选中maven项目,右键 --> maven --> update,让maven重新下载依赖包
注:此IDE自带maven插件,不需要再自己下载安装maven插件
在搭建zookeeper的过程中,使用dubbo获取的地址总是220.250.64.26,通过jdk代码调用来看,确实是这样:
InetAddress ia=null;
try {
ia=ia.getLocalHost();
String localname=ia.getHostName();
String localip=ia.getHostAddress();
System.out.println("本机名称是:"+ localname);
System.out.println("本机的ip是 :"+localip);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cosole输出:
本机名称是:bogon
本机的ip是 :220.250.64.26
220.250.64.26是虚拟的地址,导致项目在tomcat下无法正常运行。 在mac终端可以看到,本机hostname是bogon,于是我们重设hostname,命令如下:
$ sudo scutil --set HostName bianxh
$ sudo scutil --set LocalHostName bianxh
然后修改hosts文件,
bogon:redis-3.0.7 bianxh$ subl /etc/hosts
在末位新增两行:
127.0.0.1 bianxh
::1 bianxh
重新运行上面的java代码,可以看到ip地址正常了:
本机名称是:bianxh
本机的ip是 :127.0.0.1
接下来,通过dubbo注册zookeeper,可以看到console输出的注册地址就正常了,变为局域网内的本机地址。
1、确保请求参数的顺序(注意response_type和scope前后顺序):
2、确保在合适的公众号上操作,比如我在正式公众服务号上进入一个需要经过OAuth的链接,却在代码中走的测试号的appid,那也会提示这个错误。
3、如果还是不行,那再到微信管理后台确认下,修改“网页帐号-->网页授权获取用户基本信息”,使其生效,如图:
参考文档:
微信公众平台测试号管理配置页面。
首先绑定域名,方法:
设置-->公众号设置-->功能设置
然后可以设置业务域名、JS接口安全域名、网页授权域名。
将文件MP_***.txt(点击下载)例如wx.qq.com/MP_.txt;若填写路径,将文件放置在路径目录下,例如wx.qq.com/mp/.txt),并确保可以访问。
将txt拷贝到Tomcat下域名对应的路径下,配置server.xml,路径:C:\apache-tomcat-7.0.79\webapps\helloworld
a标签如果不做任何定义,点击其中的元素时,会默认跳转到主页。
<a href="" class="stars">
...
</a>
上面点击star星,就会跳转到路径"/"下,解决办法如下:
<a href="javascript:void(0)" class="stars">
...
</a>
原理是:单击此处什么也不要做,让此区域下方的组件处理href事件。
/**
* 正则表达式规则:-号出现0或者1次,0-9出现多次,小数点出现0或者1次,0-9出现多次
* @param str
* @return
*/
public static boolean isNumeric(String str) {
if (str != null && !str.isEmpty()) {
Pattern pattern = Pattern.compile("-?[0-9]*.?[0-9]*");
Matcher isNum = pattern.matcher(str);
if (isNum.matches()) {
return true;
}
}
return false;
}
<html>
<head>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
function getValue()
{
var x=document.getElementById("myHeader")
var y= $("#test #myHeader")[0];
alert(x.innerHTML);
alert(y.innerHTML);
}
</script>
</head>
<body>
<div id="test">
<h1 id="myHeader" onclick="getValue()">这是标题</h1>
</div>
<p>点击标题,会提示出它的值。</p>
</body>
</html>
Key是我申请的,可以直接用。
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="initial-scale=1.0, user-scalable=no, width=device-width">
<title>浏览器定位</title>
<link rel="stylesheet"
href="http://cache.amap.com/lbs/static/main1119.css" />
<script type="text/javascript"
src="http://webapi.amap.com/maps?v=1.3&key=b6df90d2cfda9508fb2106ae6273d7ea"></script>
<script type="text/javascript"
src="http://cache.amap.com/lbs/static/addToolbar.js"></script>
<body>
<div id='container'></div>
<div id="tip"></div>
<script type="text/javascript">
var map, geolocation;
//加载地图,调用浏览器定位服务
map = new AMap.Map('container', {
resizeEnable: true
});
map.plugin('AMap.Geolocation', function() {
geolocation = new AMap.Geolocation({
enableHighAccuracy: true,//是否使用高精度定位,默认:true
timeout: 10000, //超过10秒后停止定位,默认:无穷大
buttonOffset: new AMap.Pixel(10, 20),//定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
zoomToAccuracy: true, //定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
buttonPosition:'RB'
});
map.addControl(geolocation);
geolocation.getCurrentPosition();
AMap.event.addListener(geolocation, 'complete', onComplete);//返回定位信息
AMap.event.addListener(geolocation, 'error', onError); //返回定位出错信息
});
//解析定位结果
function onComplete(data) {
var str=['定位成功'];
str.push('经度:' + data.position.getLng());
str.push('纬度:' + data.position.getLat());
if(data.accuracy){
str.push('精度:' + data.accuracy + ' 米');
}//如为IP精确定位结果则没有精度信息
str.push('是否经过偏移:' + (data.isConverted ? '是' : '否'));
var point = data.position.getLng()+","+data.position.getLat();
poiToaddress(point);
document.getElementById('tip').innerHTML = str.join('<br>');
}
//解析定位错误信息
function onError(data) {
document.getElementById('tip').innerHTML = '定位失败';
}
//坐标点转地址
function poiToaddress(poi) {
AMap.plugin(["AMap.Geocoder"], function () {
var geocoder = new AMap.Geocoder({
city: "0315", //城市,默认:“全国”
radius: 500 //范围,默认:500,以已知坐标为中心点,radius为半径,返回范围内兴趣点和道路信息
});
geocoder.getAddress(poi, function (status, result) {
if (status === 'complete' && result.info === 'OK') {
var address = result.regeocode.formattedAddress; //返回地址描述
address2point(address);
console.log("地址::"+address);
alert("当前地址:" + address);
}
});
})
}
//地址转坐标
function address2point(address) {
AMap.plugin(["AMap.Geocoder"], function () {
var geocoder = new AMap.Geocoder({
city: "0315", //城市,默认:“全国”
radius: 500 //范围,默认:500,以已知坐标为中心点,radius为半径,返回范围内兴趣点和道路信息
});
geocoder.getLocation(address, function (status, result) {
if (status === 'complete' && result.info === 'OK') {
var geocode = result.geocodes[0];
var resultStr = geocode.location.lng + "," + geocode.location.lat;
console.log(resultStr);
alert("resultStr" + resultStr);
}
});
})
}
</script>
</body>
</html>
使用XStream,下载地址:XStream - Download
从里面找上门的3个jar包并加载。
之前的css代码是这样写(资源使用的是绝对路径):
background: url(resources/img/star2.png) no-repeat !important;
结果报资源找不见:
zepto.min.js:1 GET http://localhost:8080/helloworld/resources/static/css/resources/img/star2.png 404 (Not Found)
图片加载失败,找了一下,这个位置其实是有这个文件的:
改成相对路径就好了:
background: url(../img/star2.png) no-repeat !important;
在Eclipse下提示:
Can not find the tag library descriptor for “http://java.sun.com/jsp/jstl/core”
访问对应的页面时,console控制台提示:
The absolute uri: [http://java.sun.com/jsp/jstl/core] cannot be resolved in either web.xml or the jar files deployed with this application
从Tomcat官网去下载JSTL jar包,链接是:Apache Taglibs Downloads
注意这4个都下载:
拷贝下载后的文件到tomcat lib下,如图:
右键点击Eclipse下对应的Project,Build path --> Config Build Path,进入Liabraries标签页,添加Liabrary,如下:
如果添加了项目到tomcat下那么按照下面的步骤进行配置
1、找到Server面板,右击当前的那个Tomcat,先remove掉其中所有的工程。
2、再右击那个Tomcat,选择Clean,清空一下。
注意:只有clean之后,才能编辑Server Locations。
3、双击那个Tomcat,会打开属性面板,找到左边第二个Server Locations。
选择第二个会在Tomcat路径下创建一个名为wtpwebapps文件夹,存放Tomcat发布的web项目;
选择第三个,你可以在Server Path中输入你想要的路径,保存即可。
然后右击Server,Add and Remove...就可以添加项目来试试看了。
<fmt:formatNumber type="number" value="${8/7}" maxFractionDigits="0"/>
其中maxFractionDigits="0"表示保留0位小数,这样就可以实现取整了。同时这里是按照四舍五入的规则来进行取整的。如果是${2/6}结果就是0,如果是${6/7}结果就是1。 在这里我们同样也可以设置保留n为小数,仅需要设置maxFractionDigits="n"即可实现。
去掉form表单的这个属性:
target='hiddenwin'
- 查询报名记录
select o.id as id, o.name as org_name from t_sign_up t, t_student s, t_org o where t.student_id = s.id and s.org_id=o.id
结果如下,可以看到1个单位下有4条报名记录,另外一个单位下有2条:
- 汇总报名记录,并按照统计次数降序:
select o.id as id, o.name as org_name, count(t.id) as org_count from t_sign_up t, t_student s, t_org o where t.student_id = s.id and s.org_id=o.id group by o.name order by org_count desc
效果如下:
如上sql,在Mysql测试成功,移植到hql时,需要给经过重名的orgCount加上引号,否则会报出现报错,报找不到orgCount字段,如下:
select o.id as id, o.name as orgName, count(t.id) as orgCount from SignUp t, Student s, Org o where t.studentId = s.id and s.orgId=o.id group by o.name order by 'orgCount' desc
数据比较多的时候,需要进行分页展示,相关的,我们要构建countQuery来查询结果总数目,在如上的sql上进行统计,如下:
String countQuery = "select count(*) from (select o.id as id, o.name as orgName, count(t.id) as orgCount from SignUp t, Student s, Org o where t.studentId = s.id and s.orgId=o.id group by o.name) as result"
执行过程中,会报错:
九月 08, 2017 3:22:22 下午 org.hibernate.hql.ast.ErrorCounter reportError
严重: line 1:61: unexpected token: count
ERROR 2017 09 08 15:22:22 com.opensymphony.xwork2.util.logging.commons.CommonsLogger.error(CommonsLogger.java:42) Exception occurred during processing request: unexpected token: ( near line 1, column 22 [select count(*) from (select o.id as id, o.name as orgName, count(t.id) as orgCount from com.lmscn.lms.model.SignUp t, com.lmscn.lms.model.Student s, com.lmscn.lms.model.Org o where t.studentId = s.id and s.orgId=o.id group by o.name) as result]; nested exception is org.hibernate.hql.ast.QuerySyntaxException: unexpected token: ( near line 1, column 22 [select count(*) from (select o.id as id, o.name as orgName, count(t.id) as orgCount from com.lmscn.lms.model.SignUp t, com.lmscn.lms.model.Student s, com.lmscn.lms.model.Org o where t.studentId = s.id and s.orgId=o.id group by o.name) as result]
org.springframework.orm.hibernate3.HibernateQueryException: unexpected token: ( near line 1, column 22 [select count(*) from (select o.id as id, o.name as orgName, count(t.id) as orgCount from com.lmscn.lms.model.SignUp t, com.lmscn.lms.model.Student s, com.lmscn.lms.model.Org o where t.studentId = s.id and s.orgId=o.id group by o.name) as result]; nested exception is org.hibernate.hql.ast.QuerySyntaxException: unexpected token: ( near line 1, column 22 [select count(*) from (select o.id as id, o.name as orgName, count(t.id) as orgCount from com.lmscn.lms.model.SignUp t, com.lmscn.lms.model.Student s, com.lmscn.lms.model.Org o where t.studentId = s.id and s.orgId=o.id group by o.name) as result]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:660)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:339)
at javacommon.base.BaseHibernateDao$PageQueryUtils.pageQuery(BaseHibernateDao.java:151)
at javacommon.base.BaseHibernateDao$PageQueryUtils.access$1(BaseHibernateDao.java:147)
at javacommon.base.BaseHibernateDao.pageQuery(BaseHibernateDao.java:121)
还是hibernate解析过程中出了问题,主要是对中间产生的result虚拟临时表
没有办法识别,难道这就要放弃,只能使用JDBC来进行分页了?
不然!经过思考,我们统计count的目的就是为了得到总数,也有一个折中的办法,如下:
使用distinct进行去重,这样查到两条记录(也就是说共有两个单位),如下:
select count(distinct o.id) from t_sign_up t, t_student s, t_org o where t.student_id = s.id and s.org_id=o.id
转换成hql,如下:
String countQuery = "select count(distinct o.id) from SignUp t, Student s, Org o where t.studentId = s.id and s.orgId=o.id";
结果如下:
可以看到,分页成功了:
/**
* 过滤html标签
* @param htmlStr
* @return
*/
public synchronized static String delHTMLTag(String htmlStr){
String regEx_script="<script[^>]*?>[\\s\\S]*?<\\/script>"; //定义script的正则表达式
String regEx_style="<style[^>]*?>[\\s\\S]*?<\\/style>"; //定义style的正则表达式
String regEx_html="<[^>]+>"; //定义HTML标签的正则表达式
Pattern p_script=Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE);
Matcher m_script=p_script.matcher(htmlStr);
htmlStr=m_script.replaceAll(""); //过滤script标签
Pattern p_style=Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE);
Matcher m_style=p_style.matcher(htmlStr);
htmlStr=m_style.replaceAll(""); //过滤style标签
Pattern p_html=Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
Matcher m_html=p_html.matcher(htmlStr);
htmlStr=m_html.replaceAll(""); //过滤html标签
return htmlStr.trim(); //返回文本字符串
}
最近遇到java中设置中文字符串到Mysql出现中文乱码问题。 之前的数据库链接是:
jdbcUrl=jdbc:mysql://192.168.1.123:3306/mydb?zeroDateTimeBehavior=convertToNull
改成如下就好了:
jdbcUrl=jdbc:mysql://192.168.1.123:3306/mydb?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.set(Calendar.HOUR_OF_DAY, 24);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Date start = calendar.getTime();
/**
* 计算指定日期之前或者之后的多少分钟
* @param date
* @param minute
* @return
*/
public static String getTimeByMinute(Date date, int minute) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.MINUTE, minute);
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime());
}
try {
address = new String(address.getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
微信取得消息类型的时候会报错:
// 取得消息类型
String msgType = inputMsg.getMsgType();
WXEventType.MsgType key = WXEventType.MsgType.valueOf(msgType);
switch (key) {
case WXEventType.MsgType.event:
break;
default:
break;
}
报错如下:
The qualified case label WXEventType.MsgType.event must be replaced with the unqualified enum constant event
定义中是有的,如下:
// / <summary>
// / 消息类型枚举
// / </summary>
public enum MsgType {
// / <summary>
// /文本类型
// / </summary>
text,
// / <summary>
// / 图片类型
// / </summary>
IMAGE,
// / <summary>
// / 语音类型
// / </summary>
VOICE,
// / <summary>
// / 视频类型
// / </summary>
VIDEO,
// / <summary>
// / 地理位置类型
// / </summary>
location,
// / <summary>
// / 链接类型
// / </summary>
LINK,
// / <summary>
// / 事件类型
// / </summary>
event,
// / <summary>
// / 小视频
// / </summary>
SHORTVIDEO
}
...
}
解决办法,删除WXEventType.MsgType,如下:
// 取得消息类型
String msgType = inputMsg.getMsgType();
WXEventType.MsgType key = WXEventType.MsgType.valueOf(msgType);
switch (key) {
case event:
break;
default:
break;
}
Java Integer 类的对象创建之后他的值就不能被修改,在 Integer ++ 的时候Integer是创建一个新的对象 如果要自增,怎么办呢? 可以这样:
private void test(AtomicInteger index) {
signUpStudentNum.getAndIncrement();
}
- 封装map
Map<String, Object> responseInfoMap = new HashMap<String, Object>();
responseInfoMap.put("testInfo", testInfo);
- 设置属性
setAttr("commentListInfo", responseInfoMap);
renderJsp("/WEB-INF/jsp/helloworld/hello.jsp");
- JSP页面通过EL表达式获取
${commentListInfo.testInfo.title}
1、先建立一个Maven项目,如果是老项目,也可转成maven项目,参见我之前写的一篇帮助: Myeclipse普通java项目转maven项目
2、pom.xml引用相关jar包,1.7之后支持,配置如下:
<dependencies>
<!-- <dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency> -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
tomcat7和jave EE 1.7都支持,注意引用一个,不要重复。
3、编写事件拦截处理代码: ZhiWebSocketHandler.java
package com.yyxz.main;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jfinal.handler.Handler;
import com.jfinal.kit.StrKit;
public class ZhiWebSocketHandler extends Handler {
private Pattern filterUrlRegxPattern;
public ZhiWebSocketHandler(String filterUrlRegx) {
if (StrKit.isBlank(filterUrlRegx))
throw new IllegalArgumentException("The para filterUrlRegx can not be blank.");
filterUrlRegxPattern = Pattern.compile(filterUrlRegx);
}
@Override
public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
// TODO Auto-generated method stub
if (filterUrlRegxPattern.matcher(target).find())
return ;
else {
next.handle(target, request, response, isHandled);
}
}
}
在JFinal Config中进行注册:
public class DemoConfig extends JFinalConfig {
//...
public void configHandler(Handlers me) {
me.add(new ContextPathHandler("ctx"));
me.add(new ZhiWebSocketHandler("^/websocket"));
// 也可以使用UrlSkipHandler,就不用编写Handler处理类了
// me.add(new UrlSkipHandler("^/websocket", false));
}
//...
}
4、后台监听websocket代码: WebSocketController.java
package com.yyxz.controller;
import java.io.IOException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/websocket")
public class WebSocketController {
public WebSocketController() {
System.out.println(" WebSocket init~~~");
}
@OnOpen
public void onOpen(Session session) {
System.out.println("onOpen");
}
@OnClose
public void onClose(Session session) {
System.out.println("onClose");
}
// @OnError
// public void onError(Session session) {
// System.out.println("onError");
// }
@OnMessage
public void onMessage(String requestJson, Session session)
throws IOException {
requestJson = "一一小知回复:" + requestJson;
System.out.println(requestJson);
session.getBasicRemote().sendText(requestJson);
}
}
5、在前端发起,编写页面: webSocketTest.jsp
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- for HTML5 -->
<title>Java后端WebSocket的Tomcat实现</title>
</head>
<body>
Welcome
<br />
<input id="text" type="text" />
<button onclick="send()">发送消息</button>
<hr />
<button onclick="closeWebSocket()">关闭WebSocket连接</button>
<hr />
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/yiyixiaozhi/websocket");
}
else {
alert('当前浏览器 Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
结果如下:
请求转发使用forwardAction,请求参数会带过去,不要在请求中带参数,比如:
forwardAction("/api/test/toPage?openId=1");
正确的写法是:
forwardAction("/api/test/toPage");
使用的是高德地图,获取到中文地址后,传递到java端显示乱码,如何解决呢?
String address = getPara("address");
try {
address = new String(address.getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
统一给文件加前缀,示例如下:
bianxh:2 bianxh$ ll
total 264
drwxr-xr-x 33 bianxh staff 1122 9 16 13:43 .
drwxr-xr-x 9 bianxh staff 306 9 16 13:44 ..
-rw-r--r--@ 1 bianxh staff 397 9 16 12:26 EL表达式,结果取整.md
-rw-r--r--@ 1 bianxh staff 801 9 16 12:26 Eclipse-Java-EE-IDE修改web项目部署路径.md
-rw-r--r--@ 1 bianxh staff 2607 9 16 12:27 小结:使用正则表达式提取时间中的数字.md
bianxh:2 bianxh$ for var in *.md; do mv "$var" "2017-09-16-${var%.md}.md"; done
bianxh:2 bianxh$ ll
total 264
drwxr-xr-x 33 bianxh staff 1122 9 16 13:44 .
drwxr-xr-x 9 bianxh staff 306 9 16 13:44 ..
-rw-r--r--@ 1 bianxh staff 397 9 16 12:26 2017-09-16-EL表达式,结果取整.md
-rw-r--r--@ 1 bianxh staff 801 9 16 12:26 2017-09-16-Eclipse-Java-EE-IDE修改web项目部署路径.md
-rw-r--r--@ 1 bianxh staff 2607 9 16 12:27 2017-09-16-小结:使用正则表达式提取时间中的数字.md
还有替换啊什么的,一些高级用法,参见: https://my.oschina.net/musings/blog/380939
比如,假如文件名称中有多个后缀怎么办呢?如下:
bianxh:一一小知的副本 bianxh$ ll
total 336
drwxr-xr-x 32 bianxh staff 1088 9 16 14:04 .
drwxr-xr-x 6 bianxh staff 204 9 16 13:59 ..
-rw-r--r--@ 1 bianxh staff 6148 9 16 13:21 .DS_Store
-rw-r--r--@ 1 bianxh staff 501 9 16 12:26 2015-09-16-git代码仓库如何迁移.md
-rw-r--r--@ 1 bianxh staff 3149 9 16 12:26 2015-12-18-读笔记:公司高速发展是对团队最好的管理.md.md
-rw-r--r--@ 1 bianxh staff 3014 9 16 12:26 2015-6-2-2-如何“有效地一对一会谈”.md.md
-rw-r--r--@ 1 bianxh staff 7447 9 16 12:26 2016-09-16-OSChina git 代码fork及PR指南.md.md
-rw-r--r--@ 1 bianxh staff 163 9 16 13:24 2016-09-16-空谷幽兰-第六章-登天之道-第二节.md.md
-rw-r--r--@ 1 bianxh staff 2159 9 16 12:26 2016-1-10-吐槽招商银行营业厅,赞一下微信客服.md
-rw-r--r--@ 1 bianxh staff 3898 9 16 12:26 2016-1-16-Hunt.md
-rw-r--r--@ 1 bianxh staff 1854 9 16 12:26 2016-1-17:喜欢?电子书:纸质书.md
-rw-r--r--@ 1 bianxh staff 3708 9 16 12:26 2016-1-25:新时代的企业架构师.md
-rw-r--r--@ 1 bianxh staff 1298 9 16 12:26 2016-1-26:实践应当从业务需求出发.md
-rw-r--r--@ 1 bianxh staff 1676 9 16 12:26 2016-1-28:图像压缩技术?Lena.md
-rw-r--r--@ 1 bianxh staff 661 9 16 12:26 2016-1-28:项目经理?产品经理.md
-rw-r--r--@ 1 bianxh staff 3076 9 16 12:26 2016-10-11-内置对象.md.md
-rw-r--r--@ 1 bianxh staff 572 9 16 12:26 2016-12-1-空谷幽兰-第六章-登天之道-第三节.md.md
-rw-r--r--@ 1 bianxh staff 2464 9 16 12:26 2016-12-5-坚持很难.md.md
-rw-r--r--@ 1 bianxh staff 1298 9 16 12:26 2016-2-5-对OKRs粗浅的理解.md.md
-rw-r--r--@ 1 bianxh staff 1129 9 16 12:26 2016-4-25:软件模块的3项职责.md
-rw-r--r--@ 1 bianxh staff 2126 9 16 12:26 2016-4-27:我眼中“项目经理”需要知道的.md.md
-rw-r--r--@ 1 bianxh staff 8678 9 16 12:26 2016-5-10-“深淘滩,低作堰”-华为公司的战略创新和机制创新.md
-rw-r--r--@ 1 bianxh staff 760 9 16 12:26 2016-5-3-曲江海洋馆简游.md.md
-rw-r--r--@ 1 bianxh staff 10040 9 16 12:26 2016-5-4-樊登速读-重新定义公司.md.md
-rw-r--r--@ 1 bianxh staff 802 9 16 12:26 2016-6-14-端午节日小记.md.md
-rw-r--r--@ 1 bianxh staff 422 9 16 12:26 2016-6-15:刺猬心态.md
-rw-r--r--@ 1 bianxh staff 829 9 16 12:26 2016-6-16:球队思维.md
-rw-r--r--@ 1 bianxh staff 1011 9 16 12:26 2016-6-19:没有什么不同.md
-rw-r--r--@ 1 bianxh staff 6380 9 16 12:26 2016-7-6-OKR管理方法.md
-rw-r--r--@ 1 bianxh staff 7415 9 16 12:26 2016-9-9-[焦英俊]-阿里巴巴店铺的十年技术演变之路.md.md
-rw-r--r--@ 1 bianxh staff 8300 9 16 12:26 2017-2-1-每个程序员都应读的10本经典书籍.md.md
-rw-r--r--@ 1 bianxh staff 8833 9 16 13:25 2017-4-1-JSP.md.md
bianxh:一一小知的副本 bianxh$ rename 's/\.md.md$/\.md/' *.md
bianxh:一一小知的副本 bianxh$ ll
total 336
drwxr-xr-x 32 bianxh staff 1088 9 16 14:05 .
drwxr-xr-x 6 bianxh staff 204 9 16 13:59 ..
-rw-r--r--@ 1 bianxh staff 6148 9 16 13:21 .DS_Store
-rw-r--r--@ 1 bianxh staff 501 9 16 12:26 2015-09-16-git代码仓库如何迁移.md
-rw-r--r--@ 1 bianxh staff 3149 9 16 12:26 2015-12-18-读笔记:公司高速发展是对团队最好的管理.md
-rw-r--r--@ 1 bianxh staff 3014 9 16 12:26 2015-6-2-2-如何“有效地一对一会谈”.md
-rw-r--r--@ 1 bianxh staff 7447 9 16 12:26 2016-09-16-OSChina git 代码fork及PR指南.md
-rw-r--r--@ 1 bianxh staff 163 9 16 13:24 2016-09-16-空谷幽兰-第六章-登天之道-第二节.md
-rw-r--r--@ 1 bianxh staff 2159 9 16 12:26 2016-1-10-吐槽招商银行营业厅,赞一下微信客服.md
-rw-r--r--@ 1 bianxh staff 3898 9 16 12:26 2016-1-16-Hunt.md
-rw-r--r--@ 1 bianxh staff 1854 9 16 12:26 2016-1-17:喜欢?电子书:纸质书.md
-rw-r--r--@ 1 bianxh staff 3708 9 16 12:26 2016-1-25:新时代的企业架构师.md
-rw-r--r--@ 1 bianxh staff 1298 9 16 12:26 2016-1-26:实践应当从业务需求出发.md
-rw-r--r--@ 1 bianxh staff 1676 9 16 12:26 2016-1-28:图像压缩技术?Lena.md
-rw-r--r--@ 1 bianxh staff 661 9 16 12:26 2016-1-28:项目经理?产品经理.md
-rw-r--r--@ 1 bianxh staff 3076 9 16 12:26 2016-10-11-内置对象.md
-rw-r--r--@ 1 bianxh staff 572 9 16 12:26 2016-12-1-空谷幽兰-第六章-登天之道-第三节.md
-rw-r--r--@ 1 bianxh staff 2464 9 16 12:26 2016-12-5-坚持很难.md
-rw-r--r--@ 1 bianxh staff 1298 9 16 12:26 2016-2-5-对OKRs粗浅的理解.md
-rw-r--r--@ 1 bianxh staff 1129 9 16 12:26 2016-4-25:软件模块的3项职责.md
-rw-r--r--@ 1 bianxh staff 2126 9 16 12:26 2016-4-27:我眼中“项目经理”需要知道的.md
-rw-r--r--@ 1 bianxh staff 8678 9 16 12:26 2016-5-10-“深淘滩,低作堰”-华为公司的战略创新和机制创新.md
-rw-r--r--@ 1 bianxh staff 760 9 16 12:26 2016-5-3-曲江海洋馆简游.md
-rw-r--r--@ 1 bianxh staff 10040 9 16 12:26 2016-5-4-樊登速读-重新定义公司.md
-rw-r--r--@ 1 bianxh staff 802 9 16 12:26 2016-6-14-端午节日小记.md
-rw-r--r--@ 1 bianxh staff 422 9 16 12:26 2016-6-15:刺猬心态.md
-rw-r--r--@ 1 bianxh staff 829 9 16 12:26 2016-6-16:球队思维.md
-rw-r--r--@ 1 bianxh staff 1011 9 16 12:26 2016-6-19:没有什么不同.md
-rw-r--r--@ 1 bianxh staff 6380 9 16 12:26 2016-7-6-OKR管理方法.md
-rw-r--r--@ 1 bianxh staff 7415 9 16 12:26 2016-9-9-[焦英俊]-阿里巴巴店铺的十年技术演变之路.md
-rw-r--r--@ 1 bianxh staff 8300 9 16 12:26 2017-2-1-每个程序员都应读的10本经典书籍.md
-rw-r--r--@ 1 bianxh staff 8833 9 16 13:25 2017-4-1-JSP.md
由于MAC默认将F1、F2等按键使用了。所以正常情况下,需要通过fn+F1、F2等实现正常windows系统上的按键效果。
这个按键功能如果要和windows体验一致,操作如下:
系统偏好设置-->键盘:
但是发现还有F11、F12无法使用,比如在Chrome调试过程中,由于要使用F12键来调出开发者工具。解决办法如下:
好,我们来在Mac下远程连接Windows,打开Chrome浏览器试试:
下载的是:sh文件
bianxh:java_ee_sdk bianxh$ sudo chmod +x ./java_ee_sdk-7-jdk7-macosx-x64-ml.sh
bianxh:java_ee_sdk bianxh$ ./java_ee_sdk-7-jdk7-macosx-x64-ml.sh
This program requires DISPLAY environment variable to be set.
Please re-run after assigning an appropriate value to DISPLAY.
bianxh:java_ee_sdk bianxh$ DISPLAY=:0 ./java_ee_sdk-7-jdk7-macosx-x64-ml.sh
Extracting the installer archive...
Extracting the installer runtime...
Extracting the installer resources...
Extracting the installer metadata...
Welcome to GlassFish installer
Using the user defined JAVA_HOME : /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home
Entering setup...
SwixML 1.5 (#144)
我是先安装了jdk 8,然后安装了jdk7,通过命令可以看到,默认链接的是jdk8
bianxh:Versions bianxh$ which java
/usr/bin/java
bianxh:Versions bianxh$ ls -l /usr/bin/java
lrwxr-xr-x 1 root wheel 74 9 22 2016 /usr/bin/java -> /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java
bianxh:Versions bianxh$ /usr/libexec/java_home
/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home
bianxh:Versions bianxh$ java -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
配置~/.bash_profile
export PATH=${PATH}:/Users/bianxh/Library/Android/sdk//platform-tools
export PATH=${PATH}:/Users/bianxh/Library/Android/sdk//tools
export PATH=${PATH}:/usr/local/apache-tomcat-7.0.77/bin
export JAMES_SRC_HOME=/usr/local/james-project/james-project
# 设置 JDK 8
export JAVA_8_HOME=$(/usr/libexec/java_home -v 1.8)
# 设置 JDK 7
export JAVA_7_HOME=$(/usr/libexec/java_home -v 1.7)
export JAVA_HOME=$JAVA_7_HOME
#alias命令动态切换JDK版本
alias jdk7="export JAVA_HOME=$"JAVA_7_HOME"
alias jdk8="export JAVA_HOME=$"JAVA_8_HOME"
alias subl="'/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl'"
alias ll='ls -al'
使用命令生效配置:
bianxh:Versions bianxh$ source ~/.bash_profile
现在查看:
bianxh:Versions bianxh$ java -version
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
bianxh:Versions bianxh$ /usr/libexec/java_home -v 1.7
/Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home
bianxh:Versions bianxh$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home
以后就可以通过命令自由切换了,效果如下:
bianxh:libexec bianxh$ jdk8
bianxh:libexec bianxh$ java -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
bianxh:libexec bianxh$ jdk7
bianxh:libexec bianxh$ java -version
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
当然,如果用eclipse,注意修改JAVA_HOME,在~/.bash_profile中修改。
开发者工具:option+command+i javascript控制台:option+command+j 或者按option+command+c也可以打开
1、先解决在项目上右键单击,没有出现Configure菜单的问题,因为此菜单的下级有Convert to Maven Project 解决办法: window-->Preferences-->General-->Capabilities-->My Eclipse Standard Tools-->Advenced,勾选如下两项:
2、转maven项目,自己输入
<name>yiyixiaozhi-maven</name>
<description>maven配置</description>
3、以要使用websoket为例,添加依赖关系
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>yiyixiaozhi</groupId>
<artifactId>yiyixiaozhi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>yiyixiaozhi-maven</name>
<description>maven配置</description>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
备注:自己也可以设定maven的配置文件,settings.xml
建立一个C:\Users\zqzx.m2\settings.xml,源码如下:
<?xml version="1.0"?>
<settings>
<localRepository>~/.m2/repository</localRepository><!--需要改成自己的maven的本地仓库地址-->
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<profiles>
<profile>
<id>nexus</id>
<repositories>
<repository>
<id>nexus</id>
<name>local private nexus</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>local private nexus</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile></profiles>
</settings>
下载成功了,如下:
select * from t_class_info where date_format(now(),'%Y-%m-%d-%H-%i-%S')>=begin_date and date_format(now(),'%Y-%m-%d-%H-%i-%S')<=date_format(end_date,'%Y-%m-%d-24-00-00')
关键是这句:
date_format(now(),'%Y-%m-%d-%H-%i-%S')<=date_format(end_date,'%Y-%m-%d-24-00-00')
表定义如下:
CREATE TABLE `t_seat` (
`id` bigint(20) NOT NULL,
...
`type` enum('seat','passage') DEFAULT NULL COMMENT '座位类型(座位、过道)',
...
PRIMARY KEY (`id`),
KEY `place_id` (`place_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='座位表'
如果要更新type,使用如下语句:
update t_seat a set a.type = 'seat' where a.type = ''
不能这么使用:
update t_seat a set a.type = 'seat' where a.type is null
select * from t_class_info where place_id = 10 and date_format(now(),'%Y-%m-%d-%H-%i-%S')>=begin_date and date_format(now(),'%Y-%m-%d-%H-%i-%S')<=date_add(end_date, interval '1 00:00:00' day_second)
参考:MySQL:日期函数、时间函数总结 - ggjucheng - 博客园
假如jsp页面使用了utf-8编码。但是声明如下:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
实际运行过程就会中文乱码问题,改成如下就好了:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
解决root账号无法登陆的问题: 修改my-default.ini,重命名为my.ini,修改文件内容:
# basedir = C:\Program Files\MySQL\MySQL Server 5.7
# datadir = C:\Program Files\MySQL\MySQL Server 5.7\data
在“C:\Program Files\MySQL\MySQL Server 5.7”下创建data文件夹 管理员运行cmd,输入:mysqld -install,显示安装成功;再输入:net start mysql 输入:mysqld --initialize --user=mysql --console 得到临时密码 启动服务net start mysql; 进入mysql命令下:mysql -u root -p,输入刚刚的密码; 更新root密码:mysql> set password for root@localhost = password('123');
解决无法在局域网通过sqlyog客户端链接mysql server的问题:
mysql>use mysql;
mysql>update user set host = '%' where user = 'root';
重启mysql服务后生效。
1、安装:
sudo apt-get install mysql-server
2.检查是否安装成功:
sudo netstat -tap | grep mysql
3.允许远程连接:
sudo vim /etc/mysql/my.cnf
把 bind-address这一行 注释掉,或者改为: bind-address = 0.0.0.0
4.重启 MySQL:
netstat -tap | grep mysql
tcp 0 0 localhost:mysql *:* LISTEN 23381/mysqld
root@jdu4e00u53f7:/# service mysql restart
mysql stop/waiting
mysql start/running, process 25300
5.授权用户能进行远程连接: 首先进入mysql命令行
mysql -u root -p
mysql> grant all privileges on *.* to root@"%" identified by "password" with grant option;
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> exit
Bye
输入root安装mysql时,password使用安装时候设置的root用户密码。 然后执行:
最后用SQLyog测试一下:
假如要授权某个用户访问,方法如下: 修改 Mysql-Server 用户配置 mysql> USE mysql; -- 切换到 mysql DB Database changed mysql> SELECT User, Password, Host FROM user; -- 查看现有用户,密码及允许连接的主机 +------+----------+-----------+ | User | Password | Host | +------+----------+-----------+ | root | | localhost | +------+----------+-----------+ 1 row in set (0.00 sec) mysql> -- 只有一个默认的 root 用户, 密码为空, 只允许 localhost 连接 mysql> -- 下面我们另外添加一个新的 root 用户, 密码为空, 只允许 192.168.1.100 连接 mysql> GRANT ALL PRIVILEGES ON . TO 'root'@'192.168.1.100' IDENTIFIED BY '' WITH GRANT OPTION; 或允许所有ip访问: mysql> GRANT ALL PRIVILEGES ON . TO root@"%" IDENTIFIED BY ''; mysql> -- 当然我们也可以直接用 UPDATE 更新 root 用户 Host, 但不推荐, SQL如下: mysql> -- UPDATE user SET Host='192.168.1.100' WHERE User='root' AND Host='localhost' LIMIT 1;
Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'information_schema.PROFILING.SEQ' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
解决办法,去掉ONLY_FULL_GROUP_BY,重新设置值。
select @@global.sql_mode
set @@global.sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
设置servlet请求和响应为utf-8,如下:
HttpServletRequest request = this.getRequest();
HttpServletResponse response = this.getResponse();
try {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Quartz任务中对于时间的设定,有一定的规则,比如: "05 39 21 27 8 ? 2017" 从数据库取出来的时间格式不是这样的,是这样的: 2017-08-17 10:55:00 所以我们要提取其中的数字,代码如下:
// 分割符是 "-" 或 空格" " 或冒号 ":"
String time = "2017-08-17 10:55:00";
String[] times = time.split("[\\-:\\s]{1,}");
结果如下:
对了,还需要反转,才能对上:
List<String> timesList = Arrays.asList(times);
Collections.reverse(timesList);
times = (String[]) timesList.toArray();
如下:
什么?还缺一个问号? 由于Arrays.asList(times);返回的是一个固定长度的List,这次要折腾一下了:
String time = "2017-08-17 10:55:00";
// 分割符是 "-" 或 空格" " 或冒号 ":"
String[] times = time.split("[\\-:\\s]{1,}");
List<String> timesList = Arrays.asList(times);
List<String> flexibleTimesList = new ArrayList<String>();
flexibleTimesList.addAll(timesList);
flexibleTimesList.add(1,"?");
Collections.reverse(flexibleTimesList);
String[] resultTimes = new String[flexibleTimesList.size()];
for (String str : flexibleTimesList) {
System.out.println(str);
}
resultTimes = (String[]) flexibleTimesList.toArray();
打印都出来了,如下:
00
55
10
17
08
?
2017
但是走到最后一句,结果报错:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
at com.test.hello.Main.main(Main.java:38)
为什么呢? 因为toArray()返回的是Object[] java.util.List.toArray(),强转String[]有问题。改用如下的办法:
flexibleTimesList.toArray(resultTimes);
OK了,看看结果:
最后,别忘了转换,如下:
StringBuffer sb = new StringBuffer();
for(String str : resultTimes) {
sb.append(str + " ");
}
// 干掉最后一个空格
time = sb.toString().substring(0, sb.length() - 1);
System.out.println("{" + time + "}");
注:StringBuffer 比StringBuilder线程安全,比String +执行效率高,用这个连接字符串最合适。
打印结果如下,多余的空格也剔除了:
{00 55 10 17 08 ? 2017}
使用Quartz 2.2.3开启定时任务,每个整点获取一次,如下:
String jobName = "GetWeixinAccessToken";
String triggerName = jobName;
// 每个整点执行一次
quartzManager.addJob(jobName, triggerName, WeixinAccessTokenJob.class, "0 0 */1 * * ?", wxAccesstokenManager);
QuartzManager使用Spring注入:
import java.util.Date;
import java.util.List;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.stereotype.Service;
@Service
public class QuartzManager {
public static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
public void addJob(String jobName, String triggerName,
Class jobClass, String cron, Object obj) {
try {
Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName).build();
jobDetail.getJobDataMap().put("obj", obj);
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder
.newTrigger();
// 触发器名
triggerBuilder.withIdentity(triggerName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 添加一个定时任务
*
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param cron 时间设置,参考quartz说明文档
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class jobClass, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
// 任务名,任务组,任务执行类
JobDetail jobDetail= JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改任务的触发时间
* @param jobName
* @param triggerName
* @param cron
*/
public void modifyJobTime(String jobName, String triggerName,
String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder
.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder
.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
// JobDetail jobDetail =
// sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
// Class<? extends Job> jobClass = jobDetail.getJobClass();
// removeJob(jobName, jobGroupName, triggerName,
// triggerGroupName);
// addJob(jobName, jobGroupName, triggerName, triggerGroupName,
// jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一个任务的触发时间
*
* @param jobName
* @param jobGroupName
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
*/
public void modifyJobTime(String jobName,
String jobGroupName, String triggerName, String triggerGroupName, String cron) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
//JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
//Class<? extends Job> jobClass = jobDetail.getJobClass();
//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一个任务
*
* @param jobName
* @param triggerName
*/
public void removeJob(String jobName, String triggerName) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName);
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(JobKey.jobKey(jobName));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一个任务
*
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
*/
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
sched.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public static void shutdownJobs() {
try {
Scheduler sched = schedulerFactory.getScheduler();
if (!sched.isShutdown()) {
sched.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 判断JobName是否在执行队列中
* @param jobName
* @return
*/
public synchronized static boolean isJobExist(String jobName) throws SchedulerException {
boolean isExistJob = false;
Scheduler scheduler = schedulerFactory.getScheduler();
for (String groupName : scheduler.getJobGroupNames()) {
for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher
.jobGroupEquals(groupName))) {
String tmpJobName = jobKey.getName();
String jobGroup = jobKey.getGroup();
// get job's trigger
@SuppressWarnings("unchecked")
List<Trigger> triggers = (List<Trigger>) scheduler
.getTriggersOfJob(jobKey);
Date nextFireTime = triggers.get(0).getNextFireTime();
System.out.println("[jobName] : " + tmpJobName
+ " [groupName] : " + jobGroup + " - "
+ nextFireTime);
if (tmpJobName.equals(jobName)) {
return true;
}
}
}
return isExistJob;
}
}
在Spring ApplicationContext注入后,才可获取bean,web.xml配置拦截如下:
<!--Spring ApplicationContext 载入 -->
<listener>
<!-- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> -->
<listener-class>com.test.hello.ContextLoaderListenerOverWrite</listener-class>
</listener>
拦截类是为了获取manager,然后存放AccessToken到数据库中。实现如下:
public class ContextLoaderListenerOverWrite extends ContextLoaderListener {
@Override
public void contextInitialized(ServletContextEvent event) {
// TODO Auto-generated method stub
super.contextInitialized(event);
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
startGetWeixinAccessTokenJobs(applicationContext);
}
/**
* 开启整点定时任务
*/
public void startGetWeixinAccessTokenJobs(ApplicationContext ctx) {
WxBean currentBean = Utility.getAccessToken();
WxAccesstoken currentToken = new WxAccesstoken();
currentToken.setAccesstoken(currentBean.getAccess_token());
currentToken.setExpiresIn(Integer.valueOf(currentBean.getExpires_in()));
currentToken.setLastRequestTime(new Date());
QuartzManager quartzManager = (QuartzManager)ctx.getBean("quartzManager");
WxAccesstokenManager wxAccesstokenManager = (WxAccesstokenManager)ctx.getBean("wxAccesstokenManager");
WxAccesstoken dbWxToken = wxAccesstokenManager.findFirst();
if (dbWxToken == null) { // 新增Token
wxAccesstokenManager.save(currentToken);
System.out.println("新增Token:" + currentToken);
} else { // 更新Token
currentToken.setId(dbWxToken.getId());
wxAccesstokenManager.update(currentToken);
System.out.println("更新Token:" + currentToken);
}
String jobName = "GetWeixinAccessToken";
String triggerName = jobName;
// 每个整点执行一次
quartzManager.addJob(jobName, triggerName, WeixinAccessTokenJob.class, "0 0 */1 * * ?", wxAccesstokenManager);
}
}
获取微信AccessToken的办法如下:
/**
* 获取微信的AccessToken
* @return
*/
public static WxBean getAccessToken() {
WxBean bean = null;
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type", "client_credential");
params.put("appid", Constants.WEIXIN_APPID);
params.put("secret", Constants.WEIXIN_APPSECRET);
try {
String jstoken = HttpUtils.sendGet(
"https://api.weixin.qq.com/cgi-bin/token", params);
// String access_token = JSONObject.fromObject(jstoken).getString(
// "access_token"); // 获取到token并赋值保存
ObjectMapper objectMapper = JsonUtils.createObjectMapper();
try {
bean = objectMapper.readValue(jstoken, WxBean.class);
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bean;
}
对了,还有关键的部分,在这个Job里面每个整点更新AccessToken
public class WeixinAccessTokenJob implements Job{
public WeixinAccessTokenJob() {
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//打印任务详情
System.out.println( "WeixinTokenJob:" + "-" +
context.getJobDetail().getKey().getGroup()
+"——"+context.getJobDetail().getKey().getName()
+"——"+context.getTrigger().getKey().getName()
+"——"+context.getTrigger().getKey().getGroup() + new Date());
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
WxAccesstokenManager wxAccesstokenManager = (WxAccesstokenManager)jobDataMap.get("obj");
// Todo 使用wxAccesstokenManager来管理数据库存放的AccessToken
}
}
使用Jfinal新增一条数据:
new CommentRecord().set("comment_time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).set("star_level", starLevel).set("comment", commentText).save();
结果报错如下:
com.jfinal.plugin.activerecord.ActiveRecordException: java.sql.SQLException: Field 'id' doesn't have a default value at com.jfinal.plugin.activerecord.Model.save(Model.java:424)...Caused by: java.sql.SQLException: Field 'id' doesn't have a default valueat com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)...
原因是数据库对应的Table表的主键id不是自增的,修改即可:
评论需要加5颗星的功能,之前代码是这么写的:
<c:if
test="${star_level == 1}">
<i class="ys"></i>
<i></i>
<i></i>
<i></i>
<i></i>
</c:if> <c:if
test="${star_level == 2}">
<i class="ys"></i>
<i class="ys"></i>
<i></i>
<i></i>
<i></i>
</c:if> <c:if
test="${star_level == 3}">
<i class="ys"></i>
<i class="ys"></i>
<i class="ys"></i>
<i></i>
<i></i>
</c:if> <c:if
test="${star_level == 4}">
<i class="ys"></i>
<i class="ys"></i>
<i class="ys"></i>
<i class="ys"></i>
<i></i>
</c:if> <c:if
test="${star_level == 5}">
<i class="ys"></i>
<i class="ys"></i>
<i class="ys"></i>
<i class="ys"></i>
<i class="ys"></i>
</c:if>
<c:if test="${curentCommentRecord == null || star_level == 0}">
<i></i>
<i></i>
<i></i>
<i></i>
<i></i>
</c:if>
是不是看着很冗余?如果是10颗星呢?那代码就更长了,也不好维护,看着不舒服,那咋优化呢? 如下:
<c:forEach begin='1' end="5" var='item'>
<c:choose>
<c:when test="${item <= star_level }">
<i class="ys"></i>
</c:when>
<c:otherwise>
<i></i>
</c:otherwise>
</c:choose>
</c:forEach>
效果出来了,棒棒哒。
在Tomcat的server.xml或者Tomcat.xxx\conf\Catalina\localhost\project.xml文件中里Context标签内:
第二步:debug方式启动Tomcat。如果你用的是eclipse Tomcat插件的话,
将Don't run tomcat debug mode取消勾选,就是将会是debug方式启动Tomcat了:
window=>preferences=>Tomcat=>JVM Settings
如果是MyEclipse:
使用frp进行内网穿透,可以很方便地进行调试,比如微信公众号。穿透前,需要有一台能连接公网的机器,京东云最近做活动,可以免费半年。我在这上面进行了实战。
原来用的是花生壳,但是有很多限制,还是自己弄了域名比较方便。
frp是什么,就不多说了,有兴趣的童鞋看这个:https://github.com/fatedier/frp
工具在上面的github地址上可以下载到,我提供一个X86 CPU版本的windows和linux版本的地址。 链接:http://pan.baidu.com/s/1kV7R39t 密码:md3a
在公网IP服务器配置frps.ini,如下:
[common]
bind_port = 7000
vhost_http_port = 80
本地局域网配置frpc.ini
[common]
server_addr = 111.61.131.13
server_port = 7000
[ssh]
type = tcp
local_ip = 192.168.3.133
local_port = 22
remote_port = 6000
[web]
type = http
local_port = 8080
custom_domains = test.bianxh.top
公网使用的是Linux,运行命令如下:
root@***:~/frp_0.13.0_linux_386# ./frps -c ./frps.ini
2017/09/12 12:37:50 [I] [service.go:83] frps tcp listen on 0.0.0.0:7000
2017/09/12 12:37:50 [I] [service.go:108] http service listen on 0.0.0.0:80
2017/09/12 12:37:50 [I] [main.go:112] Start frps success
2017/09/12 12:37:50 [I] [main.go:114] PrivilegeMode is enabled, you should pay more attention to security issues
本地是Windows,运行命令如下:
D:\GreenSoft\frp_0.13.0_windows_amd64>frpc.exe -c frpc.ini
2017/09/12 12:35:00 [I] [control.go:276] [ded5c9fb0d273509] login to server success, get run id [ded5c9fb0d273509]
2017/09/12 12:35:01 [I] [control.go:411] [ded5c9fb0d273509] [ssh] start proxy success
2017/09/12 12:35:01 [I] [control.go:411] [ded5c9fb0d273509] [web] start proxy success
下来去服务商管理后台,配置下域名解析:
记录类型 | 主机记录 | 记录值 |
---|---|---|
A | test | 公网IP,比如:111.61.131.13 |
可以访问到本地了:
http://test.bianxh.top/yiyixiaozhi/webSocketTest.jsp
和本地访问一样,如下:
刚刷新两次,就提示无法访问了,没有备案的域名果然不好使啊: http://illegalitydomain.jcloud.com/
换个地址,使用端口访问了一下,是通的。
下来还是要乖乖备案去。