一、准备工作
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
3) 引入依赖(Servlet、Jackson)
所谓 "前后端交互接口" 是进行 Web 开发中的关键环节。
为了完成前后端交互,要约定两个交互接口:
1.从服务器上获取到所有消息:
请求: GET/message
响应: JSON 格式
{
{from:"xxx" ,to:"xxx", message:"xxxxxx"}
..............
.............
}
2.往服务器上提交数据
请求: body 也为 JSON 格式
POST/message
{from:"xxx" ,to:"xxx", message:"xxxxxx"}
响应: JSON 格式
{ok:1}
//这个类表示一条消息的数据格式
class Message{
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
// 用于转换 JSON 字符串
private ObjectMapper objectMapper = new ObjectMapper();
// 用于保存所有的留言
private List<Message> messageList = new ArrayList<>();
//doGet方法用来从服务器上获取消息
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
//writeValue就是把messageList对象转换成json格式的字符串,并通过写入响应(resp.getWriter())返回
objectMapper.writeValue(resp.getWriter(),messageList);
}
//doPost方法用来把客户端的数据提交到服务器
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//readValue第一个参数可以支持一个字符串,也可以放inputStream对象;第二个参数是用来接收读取到的结果
//返回值放到Message对象中
//通过这个代码就完成了读取body,并且解析成json的过程
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
messageList.add(message);
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("{\"ok\":1}");
}
}
<script src="https://lib.baomitu.com/jquery/1.12.4/jquery.min.js"></script>
<script>
//1.在页面加载的时候访问服务器,从服务器这边获取到消息列表,并展示出来
function load(){
$.ajax({
type:'GET',
url:'message',
success: function(data,status){
let container = document.querySelector('.container');
for(let message of data){
let row = document.createElement('div');
row.className = 'row';
row.innerHTML = message.from + '对' + message.to + '说: ' + message.message;
container.appendChild(row);
}
}
});
}
load();
//2.点击提交按钮的时候,把当前的数据构造成一个http请求,发送给服务器
let submitButon = document.querySelector('#submit');
submitButon.onclick = function(){
//1.先获取到编辑框中的内容
let edits = document.querySelectorAll('.edit');
console.log(edits);
let from = edits[0].value;
let to = edits[1].value;
let message = edits[2].value;
console.log(from+'对'+to+'说,'+message);
if(from == '' || to == '' || message == ''){
return;
}
//2.根据内容构造html元素(.row里面包含用户输入的话
let row = document.createElement('div');
row.className = 'row';
row.innerHTML = from+'对'+to+'说,'+message;
//3.把这个元素添加到DOM树上
let container = document.querySelector('.container');
container.appendChild(row);
//4.清空原来的输入框
for(let i=0; i<edits.length; i++){
edits[i].value = '';
}
//5.构造成一个http请求,发送给服务器
$.ajax({
type:'POST',
url:'message',
//data里面就是body数据
data: JSON.stringify({from:from, to:to, message:message}),
contentType: "application/json;charset=utf-8",
success: function(data,status){
if(data.ok == 1){
console.log('提交成功');
}else{
console.log('提交失败');
}
}
})
}
</script>
数据此时是存储在服务器的内存中 ( private List<Message> messages = new ArrayList<Message>(); ), 一旦服务器重启, 数据仍然会丢失。
在上面的代码中,我们是把数据保存在messageList这个变量里面的,如果我们要把数据放在文件中,进行持久化存储,就不需要这变量了。
FileWriter fileWriter = new FileWriter(filePath,true)
java打开文件主要由三种方式:
1.读方式打开(使用输入流对象的时候)
2.写方式打开(使用输出流对象的时候)这种方式会清空原有内容
3.追加写方式打开(使用输出流对象的时候) ,这种方式不会清空原有内容,而是直接在文件内容后面拼接。后面加上true就是追加写状态。
数据存入文件完整代码如下:
class Message{
public String from;
public String to;
public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
// 用于转换 JSON 字符串
private ObjectMapper objectMapper = new ObjectMapper();
// 用于保存所有的留言
// private List<Message> messageList = new ArrayList<>();
//保存文件的路径
private String filePath = "d:code/java/messageWall924/messages924.txt";
//doGet方法用来从服务器上获取消息
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
//writeValue就是把messageList对象转换成json格式的字符串,并通过写入响应(resp.getWriter())返回
List<Message> messageList = load();
objectMapper.writeValue(resp.getWriter(),messageList);
}
private List<Message> load(){
//把读到的数据放到List<Message>中
List<Message> messageList = new ArrayList<>();
System.out.println("开始从文件加载数据!");
//此处需要按行读取,FileReader不支持,需要套上一层BufferedReader
try(BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))){
while (true){
String line = bufferedReader.readLine();
if (line == null){
break;
}
//读取到的内容,就解析成Message对象
String[] tokens = line.split("\t");
Message message = new Message();
message.from = tokens[0];
message.to = tokens[1];
message.message = tokens[2];
messageList.add(message);
}
}catch (IOException e){
e.printStackTrace();
}
return messageList;
}
//doPost方法用来把客户端的数据提交到服务器
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//readValue第一个参数可以支持一个字符串,也可以放inputStream对象;第二个参数是用来接收读取到的结果
//返回值放到Message对象中
//通过这个代码就完成了读取body,并且解析成json的过程
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
//这里进行一个写文件操作
save(message);
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("{\"ok\":1}");
}
private void save(Message message){
System.out.println("数据开始写入文件");
try(FileWriter fileWriter = new FileWriter(filePath,true)){
fileWriter.write(message.from + '\t' + message.to +
'\t' + message.message + '\n');
}catch (IOException e){
e.printStackTrace();
}
}
}
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
3) 创建 DBUtil 类
public class DBUtil {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/messageWall924?characterEncoding=utf8&useSSL=false";
private static final String USERNAME = "root";
private static final String PASSWORD = "1234";
private static volatile DataSource dataSource = null;
public static DataSource getDataSource(){
if (dataSource == null){
synchronized (DBUtil.class){
if (dataSource == null){
dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL(URL);
((MysqlDataSource)dataSource).setUser(USERNAME);
((MysqlDataSource)dataSource).setPassword(PASSWORD);
}
}
}
return dataSource;
}
public static Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
if (resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//readValue第一个参数可以支持一个字符串,也可以放inputStream对象;第二个参数是用来接收读取到的结果
//返回值放到Message对象中
//通过这个代码就完成了读取body,并且解析成json的过程
Message message = objectMapper.readValue(req.getInputStream(),Message.class);
//这里进行一个写数据操作
save(message);
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("{\"ok\":1}");
}
private void save(Message message){
System.out.println("向数据库写入数据!");
//1.先和数据库建立连接
Connection connection = null;
PreparedStatement statement = null;
try {
//1.先和数据库建立连接
connection = DBUtil.getConnection();
//2.拼装sql
String sql = "insert into message values(?,?,?)";
statement = connection.prepareStatement(sql);
statement.setString(1,message.from);
statement.setString(2,message.to);
statement.setString(3,message.message);
//执行sql
int ret = statement.executeUpdate();
if (ret == 1){
System.out.println("插入数据库成功");
}else {
System.out.println("插入数据库失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,null);
}
}
//doGet方法用来从服务器上获取消息
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
//writeValue就是把messageList对象转换成json格式的字符串,并通过写入响应(resp.getWriter())返回
List<Message> messageList = load();
objectMapper.writeValue(resp.getWriter(),messageList);
}
private List<Message> load(){
//把读到的数据放到List<Message>中
List<Message> messageList = new ArrayList<>();
System.out.println("从数据库开始读取数据!");
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBUtil.getConnection();
String sql = "select * from message";
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while (resultSet.next()){
Message message = new Message();
message.from = resultSet.getString("from");
message.to = resultSet.getString("to");
message.message = resultSet.getString("message");
messageList.add(message);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,statement,resultSet);
}
return messageList;
}
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式rubyshell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f
我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳